From 7bca4aa24f47fd5fae5fe3480dfc1c36265377b9 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 7 Feb 2017 19:42:21 +0100 Subject: [PATCH 01/13] Handle registry not found errors (Fixes #4463) (#4465) --- js/src/modals/CreateWallet/createWalletStore.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/src/modals/CreateWallet/createWalletStore.js b/js/src/modals/CreateWallet/createWalletStore.js index 40c823254..213c35a36 100644 --- a/js/src/modals/CreateWallet/createWalletStore.js +++ b/js/src/modals/CreateWallet/createWalletStore.js @@ -198,6 +198,9 @@ export default class CreateWalletStore { .get() .registry .lookupAddress(walletLibraryRegKey) + .catch(() => { + return null; // exception when registry is not available + }) .then((address) => { const walletLibraryAddress = (address || '').replace(/^0x/, '').toLowerCase(); const code = walletLibraryAddress.length && !/^0+$/.test(walletLibraryAddress) From 2411e674eb73889e9a7416a4db1d5e8d4b8e2470 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 7 Feb 2017 19:55:58 +0100 Subject: [PATCH 02/13] Fixing histogram again (#4464) (#4467) --- js/src/ui/GasPriceEditor/store.js | 2 +- js/src/ui/GasPriceEditor/store.spec.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/ui/GasPriceEditor/store.js b/js/src/ui/GasPriceEditor/store.js index 867fca11a..62c3f840c 100644 --- a/js/src/ui/GasPriceEditor/store.js +++ b/js/src/ui/GasPriceEditor/store.js @@ -180,7 +180,7 @@ export default class GasPriceEditor { // NOTE fetching histogram may fail if there is not enough data. // We fallback to empty histogram. this._api.parity.gasPriceHistogram().catch(() => ({ - bucket_bounds: [], + bucketBounds: [], counts: [] })), this._api.eth.gasPrice(), diff --git a/js/src/ui/GasPriceEditor/store.spec.js b/js/src/ui/GasPriceEditor/store.spec.js index e4c0f0849..36d02c8c4 100644 --- a/js/src/ui/GasPriceEditor/store.spec.js +++ b/js/src/ui/GasPriceEditor/store.spec.js @@ -96,6 +96,7 @@ describe('ui/GasPriceEditor/Store', () => { setImmediate(() => { expect(store.histogram).not.to.be.null; + expect(store.histogram.bucketBounds).not.to.be.null; done(); }); }); From 428e8361ce8b0ce711eb1b22a380f70b217c55bd Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Tue, 7 Feb 2017 19:16:17 +0000 Subject: [PATCH 03/13] [ci skip] js-precompiled 20170207-191009 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 053527bea..e5556e1d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1574,7 +1574,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#a590186c6acf75e31b7cff259721793960ded4e1" +source = "git+https://github.com/ethcore/js-precompiled.git#13f709d44a8634fccf121205d1b0976b9527d34a" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 28d65ba48..9cb59d65f 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.3.70", + "version": "0.3.71", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 810ec3558a2dd8a69a157fbcc70fc072333a1ba2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 7 Feb 2017 16:09:59 -0500 Subject: [PATCH 04/13] Make signing compatible with geth. (#4468) --- rpc/src/v1/helpers/dispatch.rs | 8 ++++++-- rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/tests/mocked/signing.rs | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 126b26bc2..0f9e4619f 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -109,8 +109,12 @@ pub fn execute(client: &C, miner: &M, accounts: &AccountProvider, payload: .map(ConfirmationResponse::SignTransaction) ) }, - ConfirmationPayload::Signature(address, data) => { - signature(accounts, address, data.sha3(), pass) + ConfirmationPayload::Signature(address, mut data) => { + let mut message_data = + format!("\x19Ethereum Signed Message:\n{}", data.len()) + .into_bytes(); + message_data.append(&mut data); + signature(accounts, address, message_data.sha3(), pass) .map(|result| result .map(|rsv| { let mut vrs = [0u8; 65]; diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index c6476d16b..5f0e84389 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -310,7 +310,7 @@ fn rpc_eth_sign() { ], "id": 1 }"#; - let res = r#"{"jsonrpc":"2.0","result":"0x1b5100b2be0aafd86271c8f49891262920bfbfeaeccb2ef1d0b2053aefc3ddb399483eb3c902ecf4add3156461a61f59e924a65eb5e6cdbab0a158d45db5f87cdf","id":1}"#; + let res = r#"{"jsonrpc":"2.0","result":"0x1ba2870db1d0c26ef93c7b72d2a0830fa6b841e0593f7186bc6c7cc317af8cf3a42fda03bd589a49949aa05db83300cdb553116274518dbe9d90c65d0213f4af49","id":1}"#; assert_eq!(tester.io.handle_request_sync(&req), Some(res.into())); } diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 6e971511d..c70ef6d3f 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -200,7 +200,7 @@ fn should_sign_if_account_is_unlocked() { ], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x1bb3062482b0687e9c97c7609ea60c1649959dbb334f71b3d5cacd496e0848ba8137bc765756627722389c6c39bc77700ccdc8916916a0eb03bcf5191d4f74dc65","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x1bdb53b32e56cf3e9735377b7664d6de5a03e125b1bf8ec55715d253668b4238503b4ac931fe6af90add73e72a585e952665376b2b9afc5b6b239b7df74c734e12","id":1}"#; assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); assert_eq!(tester.signer.requests().len(), 0); } From 86dbd509576f88fe7f62f7ad4c56795b911df25b Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 7 Feb 2017 22:13:52 +0100 Subject: [PATCH 05/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0d7d0dca..23a1c6f73 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do $ curl https://sh.rustup.rs -sSf | sh ``` - Parity also requires `gcc`, `g++`, `libssl-dev`/`openssl` and `pkg-config` packages to be installed. + Parity also requires `gcc`, `g++`, `libssl-dev`/`openssl`, `libudev-dev` and `pkg-config` packages to be installed. - OSX: ```bash $ curl https://sh.rustup.rs -sSf | sh From b1710762152a49380486c8dd2a78874cdac97d49 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 7 Feb 2017 22:14:34 +0100 Subject: [PATCH 06/13] Update Dockerfile --- docker/hub/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/hub/Dockerfile b/docker/hub/Dockerfile index d4f5b96ee..9c2bc614f 100644 --- a/docker/hub/Dockerfile +++ b/docker/hub/Dockerfile @@ -19,6 +19,7 @@ RUN apt-get update && \ file \ openssl \ libssl-dev \ + libudev-dev \ pkg-config \ dpkg-dev \ # evmjit dependencies From 0e8b96a268ecc4c205651814714a8decdf5339d6 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 7 Feb 2017 22:15:01 +0100 Subject: [PATCH 07/13] Update Dockerfile --- docker/hub/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/hub/Dockerfile b/docker/hub/Dockerfile index 9c2bc614f..3fe0adf9c 100644 --- a/docker/hub/Dockerfile +++ b/docker/hub/Dockerfile @@ -19,7 +19,7 @@ RUN apt-get update && \ file \ openssl \ libssl-dev \ - libudev-dev \ + libudev-dev \ pkg-config \ dpkg-dev \ # evmjit dependencies From 5fe993f65885a0aaf35045858c80466ca52984ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 8 Feb 2017 00:11:42 +0100 Subject: [PATCH 08/13] Fixing CORS headers for parity.web3.site (#4461) --- dapps/src/api/cors.rs | 0 dapps/src/handlers/mod.rs | 2 +- dapps/src/lib.rs | 19 +++++++++++--- dapps/src/proxypac.rs | 3 ++- dapps/src/router/mod.rs | 2 +- dapps/src/tests/api.rs | 54 +++++++++++++++++++++++++++++++++++++++ ethcore/src/trace/db.rs | 4 +-- 7 files changed, 76 insertions(+), 8 deletions(-) delete mode 100644 dapps/src/api/cors.rs diff --git a/dapps/src/api/cors.rs b/dapps/src/api/cors.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs index 51964648d..cec7be631 100644 --- a/dapps/src/handlers/mod.rs +++ b/dapps/src/handlers/mod.rs @@ -43,7 +43,7 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Option if let Some(embeddable_on) = embeddable_on { headers.set_raw( "X-Frame-Options", - vec![format!("ALLOW-FROM http://{}", address(embeddable_on)).into_bytes()] + vec![format!("ALLOW-FROM http://{}", address(&embeddable_on)).into_bytes()] ); } else { // TODO [ToDr] Should we be more strict here (DENY?)? diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index 50dcb39b1..cd4479525 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -253,7 +253,12 @@ impl Server { match signer_address { Some(signer_address) => vec![ format!("http://{}{}", HOME_PAGE, DAPPS_DOMAIN), - format!("http://{}", address(signer_address)), + format!("http://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1), + format!("http://{}", address(&signer_address)), + format!("https://{}{}", HOME_PAGE, DAPPS_DOMAIN), + format!("https://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1), + format!("https://{}", address(&signer_address)), + ], None => vec![], } @@ -377,7 +382,7 @@ fn random_filename() -> String { rng.gen_ascii_chars().take(12).collect() } -fn address(address: (String, u16)) -> String { +fn address(address: &(String, u16)) -> String { format!("{}:{}", address.0, address.1) } @@ -411,6 +416,14 @@ mod util_tests { // then assert_eq!(none, Vec::::new()); - assert_eq!(some, vec!["http://parity.web3.site".to_owned(), "http://127.0.0.1:18180".into()]); + assert_eq!(some, vec![ + "http://parity.web3.site".to_owned(), + "http://parity.web3.site:18180".into(), + "http://127.0.0.1:18180".into(), + "https://parity.web3.site".into(), + "https://parity.web3.site:18180".into(), + "https://127.0.0.1:18180".into() + + ]); } } diff --git a/dapps/src/proxypac.rs b/dapps/src/proxypac.rs index 8a4249476..16459d88e 100644 --- a/dapps/src/proxypac.rs +++ b/dapps/src/proxypac.rs @@ -35,7 +35,8 @@ impl ProxyPac { impl Endpoint for ProxyPac { fn to_handler(&self, path: EndpointPath) -> Box { - let signer = self.signer_address.clone() + let signer = self.signer_address + .as_ref() .map(address) .unwrap_or_else(|| format!("{}:{}", path.host, path.port)); diff --git a/dapps/src/router/mod.rs b/dapps/src/router/mod.rs index dbaf4dbb0..f34151552 100644 --- a/dapps/src/router/mod.rs +++ b/dapps/src/router/mod.rs @@ -138,7 +138,7 @@ impl server::Handler for Router { }, // Redirect any other GET request to signer. _ if is_get_request => { - if let Some(signer_address) = self.signer_address.clone() { + if let Some(ref signer_address) = self.signer_address { trace!(target: "dapps", "Redirecting to signer interface."); Redirection::boxed(&format!("http://{}", address(signer_address))) } else { diff --git a/dapps/src/tests/api.rs b/dapps/src/tests/api.rs index 05e285264..0930aa0ce 100644 --- a/dapps/src/tests/api.rs +++ b/dapps/src/tests/api.rs @@ -158,3 +158,57 @@ fn should_return_signer_port_cors_headers_for_home_parity() { response.headers ); } + + +#[test] +fn should_return_signer_port_cors_headers_for_home_parity_with_https() { + // given + let server = serve(); + + // when + let response = request(server, + "\ + POST /api/ping HTTP/1.1\r\n\ + Host: localhost:8080\r\n\ + Origin: https://parity.web3.site\r\n\ + Connection: close\r\n\ + \r\n\ + {} + " + ); + + // then + assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned()); + assert!( + response.headers_raw.contains("Access-Control-Allow-Origin: https://parity.web3.site"), + "CORS header for parity.web3.site missing: {:?}", + response.headers + ); +} + +#[test] +fn should_return_signer_port_cors_headers_for_home_parity_with_port() { + // given + let server = serve(); + + // when + let response = request(server, + "\ + POST /api/ping HTTP/1.1\r\n\ + Host: localhost:8080\r\n\ + Origin: http://parity.web3.site:18180\r\n\ + Connection: close\r\n\ + \r\n\ + {} + " + ); + + // then + assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned()); + assert!( + response.headers_raw.contains("Access-Control-Allow-Origin: http://parity.web3.site:18180"), + "CORS header for parity.web3.site missing: {:?}", + response.headers + ); +} + diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs index cbd0ce3d9..206f1cb7e 100644 --- a/ethcore/src/trace/db.rs +++ b/ethcore/src/trace/db.rs @@ -16,7 +16,7 @@ //! Trace database. use std::ops::Deref; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::sync::Arc; use bloomchain::{Number, Config as BloomConfig}; use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, BloomGroup}; @@ -305,7 +305,7 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { } fn trace(&self, block_number: BlockNumber, tx_position: usize, trace_position: Vec) -> Option { - let trace_position_deq = trace_position.into_iter().collect(); + let trace_position_deq = trace_position.into_iter().collect::>(); self.extras.block_hash(block_number) .and_then(|block_hash| self.transactions_traces(&block_hash) .and_then(|traces| traces.into_iter().nth(tx_position)) From b0248cad0b039b2baccd58757029770fe203475e Mon Sep 17 00:00:00 2001 From: keorn Date: Wed, 8 Feb 2017 02:55:56 -0500 Subject: [PATCH 09/13] sort corpus when hitting genesis (#4470) --- ethcore/src/client/traits.rs | 1 + ethcore/src/tests/client.rs | 7 +++++++ util/src/stats.rs | 1 + 3 files changed, 9 insertions(+) diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index dfb251296..dce708b3a 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -220,6 +220,7 @@ pub trait BlockChainClient : Sync + Send { let block = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed"); let header = block.header_view(); if header.number() == 0 { + corpus.sort(); return corpus; } block.transaction_views().iter().foreach(|t| corpus.push(t.gas_price())); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index abaf1cc3b..6c2c02c2d 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -233,6 +233,13 @@ fn empty_gas_price_histogram() { assert!(client.gas_price_histogram(20, 5).is_none()); } +#[test] +fn corpus_is_sorted() { + let client_result = generate_dummy_client_with_data(2, 1, slice_into![U256::from_str("11426908979").unwrap(), U256::from_str("50426908979").unwrap()]); + let client = client_result.reference(); + let corpus = client.gas_price_corpus(20); + assert!(corpus[0] < corpus[1]); +} #[test] fn can_handle_long_fork() { diff --git a/util/src/stats.rs b/util/src/stats.rs index e82447552..c4c08ddc8 100644 --- a/util/src/stats.rs +++ b/util/src/stats.rs @@ -33,6 +33,7 @@ impl Histogram { if corpus.len() < 1 { return None; } let corpus_end = corpus.last().expect("there is at least 1 element; qed").clone(); let corpus_start = corpus.first().expect("there is at least 1 element; qed").clone(); + trace!(target: "stats", "Computing histogram from {} to {} with {} buckets.", corpus_start, corpus_end, bucket_number); // Bucket needs to be at least 1 wide. let bucket_size = { // Round up to get the entire corpus included. From a92bf651819a155dfb6b3ebfaeefaaee831646f2 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 8 Feb 2017 15:53:39 +0300 Subject: [PATCH 10/13] parity_getVaultMeta && parity_setVaultMeta (#4475) --- ethcore/src/account_provider/mod.rs | 12 ++++ ethstore/src/dir/disk.rs | 2 +- ethstore/src/dir/mod.rs | 4 ++ ethstore/src/dir/vault.rs | 80 +++++++++++++++++----- ethstore/src/ethstore.rs | 22 ++++++ ethstore/src/json/vault_file.rs | 16 +++-- ethstore/src/secret_store.rs | 4 ++ rpc/src/v1/impls/parity_accounts.rs | 13 ++++ rpc/src/v1/tests/mocked/parity_accounts.rs | 24 +++++++ rpc/src/v1/traits/parity_accounts.rs | 8 +++ 10 files changed, 162 insertions(+), 23 deletions(-) diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 95b2ad855..6bb85eb59 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -493,6 +493,18 @@ impl AccountProvider { .map_err(Into::into) .map(|_| ()) } + + /// Get vault metadata string. + pub fn get_vault_meta(&self, name: &str) -> Result { + self.sstore.get_vault_meta(name) + .map_err(Into::into) + } + + /// Set vault metadata string. + pub fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> { + self.sstore.set_vault_meta(name, meta) + .map_err(Into::into) + } } #[cfg(test)] diff --git a/ethstore/src/dir/disk.rs b/ethstore/src/dir/disk.rs index f78dba288..9162f8508 100755 --- a/ethstore/src/dir/disk.rs +++ b/ethstore/src/dir/disk.rs @@ -158,7 +158,7 @@ impl DiskDirectory where T: KeyFileManager { Ok(account) } - /// Get key file manager + /// Get key file manager referece pub fn key_manager(&self) -> &T { &self.key_manager } diff --git a/ethstore/src/dir/mod.rs b/ethstore/src/dir/mod.rs index 356fb5b07..79890650b 100755 --- a/ethstore/src/dir/mod.rs +++ b/ethstore/src/dir/mod.rs @@ -84,6 +84,10 @@ pub trait VaultKeyDirectory: KeyDirectory { fn key(&self) -> VaultKey; /// Set new key for vault fn set_key(&self, key: VaultKey) -> Result<(), SetKeyError>; + /// Get vault meta + fn meta(&self) -> String; + /// Set vault meta + fn set_meta(&self, meta: &str) -> Result<(), Error>; } pub use self::disk::RootDiskDirectory; diff --git a/ethstore/src/dir/vault.rs b/ethstore/src/dir/vault.rs index c068388f3..8699a9e49 100755 --- a/ethstore/src/dir/vault.rs +++ b/ethstore/src/dir/vault.rs @@ -16,6 +16,7 @@ use std::{fs, io}; use std::path::{PathBuf, Path}; +use parking_lot::Mutex; use {json, SafeAccount, Error}; use util::sha3::Hashable; use super::super::account::Crypto; @@ -24,6 +25,8 @@ use super::disk::{DiskDirectory, KeyFileManager}; /// Name of vault metadata file pub const VAULT_FILE_NAME: &'static str = "vault.json"; +/// Name of temporary vault metadata file +pub const VAULT_TEMP_FILE_NAME: &'static str = "vault_temp.json"; /// Vault directory implementation pub type VaultDiskDirectory = DiskDirectory; @@ -32,6 +35,7 @@ pub type VaultDiskDirectory = DiskDirectory; pub struct VaultKeyFileManager { name: String, key: VaultKey, + meta: Mutex, } impl VaultDiskDirectory { @@ -44,13 +48,14 @@ impl VaultDiskDirectory { } // create vault && vault file + let vault_meta = "{}"; fs::create_dir_all(&vault_dir_path)?; - if let Err(err) = create_vault_file(&vault_dir_path, &key) { + if let Err(err) = create_vault_file(&vault_dir_path, &key, vault_meta) { let _ = fs::remove_dir_all(&vault_dir_path); // can't do anything with this return Err(err); } - Ok(DiskDirectory::new(vault_dir_path, VaultKeyFileManager::new(name, key))) + Ok(DiskDirectory::new(vault_dir_path, VaultKeyFileManager::new(name, key, vault_meta))) } /// Open existing vault directory with given key @@ -62,9 +67,9 @@ impl VaultDiskDirectory { } // check that passed key matches vault file - check_vault_file(&vault_dir_path, &key)?; + let meta = read_vault_file(&vault_dir_path, &key)?; - Ok(DiskDirectory::new(vault_dir_path, VaultKeyFileManager::new(name, key))) + Ok(DiskDirectory::new(vault_dir_path, VaultKeyFileManager::new(name, key, &meta))) } fn create_temp_vault(&self, key: VaultKey) -> Result { @@ -145,13 +150,26 @@ impl VaultKeyDirectory for VaultDiskDirectory { temp_vault.delete().map_err(|err| SetKeyError::NonFatalNew(err)) } + + fn meta(&self) -> String { + self.key_manager().meta.lock().clone() + } + + fn set_meta(&self, meta: &str) -> Result<(), Error> { + let key_manager = self.key_manager(); + let vault_path = self.path().expect("self is instance of DiskDirectory; DiskDirectory always returns path; qed"); + create_vault_file(vault_path, &key_manager.key, meta)?; + *key_manager.meta.lock() = meta.to_owned(); + Ok(()) + } } impl VaultKeyFileManager { - pub fn new(name: &str, key: VaultKey) -> Self { + pub fn new(name: &str, key: VaultKey, meta: &str) -> Self { VaultKeyFileManager { name: name.into(), key: key, + meta: Mutex::new(meta.to_owned()), } } } @@ -199,29 +217,37 @@ fn check_vault_name(name: &str) -> bool { } /// Vault can be empty, but still must be pluggable => we store vault password in separate file -fn create_vault_file

(vault_dir_path: P, key: &VaultKey) -> Result<(), Error> where P: AsRef { +fn create_vault_file

(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef { let password_hash = key.password.sha3(); let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations); let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into(); vault_file_path.push(VAULT_FILE_NAME); + let mut temp_vault_file_path: PathBuf = vault_dir_path.as_ref().into(); + temp_vault_file_path.push(VAULT_TEMP_FILE_NAME); - let mut vault_file = fs::File::create(vault_file_path)?; + // this method is used to rewrite existing vault file + // => write to temporary file first, then rename temporary file to vault file + let mut vault_file = fs::File::create(&temp_vault_file_path)?; let vault_file_contents = json::VaultFile { crypto: crypto.into(), + meta: Some(meta.to_owned()), }; vault_file_contents.write(&mut vault_file).map_err(|e| Error::Custom(format!("{:?}", e)))?; + drop(vault_file); + fs::rename(&temp_vault_file_path, &vault_file_path)?; Ok(()) } -/// When vault is opened => we must check that password matches -fn check_vault_file

(vault_dir_path: P, key: &VaultKey) -> Result<(), Error> where P: AsRef { +/// When vault is opened => we must check that password matches && read metadata +fn read_vault_file

(vault_dir_path: P, key: &VaultKey) -> Result where P: AsRef { let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into(); vault_file_path.push(VAULT_FILE_NAME); let vault_file = fs::File::open(vault_file_path)?; let vault_file_contents = json::VaultFile::load(vault_file).map_err(|e| Error::Custom(format!("{:?}", e)))?; + let vault_file_meta = vault_file_contents.meta.unwrap_or("{}".to_owned()); let vault_file_crypto: Crypto = vault_file_contents.crypto.into(); let password_bytes = vault_file_crypto.decrypt(&key.password)?; @@ -230,7 +256,7 @@ fn check_vault_file

(vault_dir_path: P, key: &VaultKey) -> Result<(), Error> w return Err(Error::InvalidPassword); } - Ok(()) + Ok(vault_file_meta) } #[cfg(test)] @@ -238,8 +264,8 @@ mod test { use std::fs; use std::io::Write; use std::path::PathBuf; - use dir::VaultKey; - use super::{VAULT_FILE_NAME, check_vault_name, make_vault_dir_path, create_vault_file, check_vault_file, VaultDiskDirectory}; + use dir::{VaultKey, VaultKeyDirectory}; + use super::{VAULT_FILE_NAME, check_vault_name, make_vault_dir_path, create_vault_file, read_vault_file, VaultDiskDirectory}; use devtools::RandomTempPath; #[test] @@ -283,7 +309,7 @@ mod test { fs::create_dir_all(&vault_dir).unwrap(); // when - let result = create_vault_file(&vault_dir, &key); + let result = create_vault_file(&vault_dir, &key, "{}"); // then assert!(result.is_ok()); @@ -293,7 +319,7 @@ mod test { } #[test] - fn check_vault_file_succeeds() { + fn read_vault_file_succeeds() { // given let temp_path = RandomTempPath::create_dir(); let key = VaultKey::new("password", 1024); @@ -307,14 +333,14 @@ mod test { } // when - let result = check_vault_file(&dir, &key); + let result = read_vault_file(&dir, &key); // then assert!(result.is_ok()); } #[test] - fn check_vault_file_fails() { + fn read_vault_file_fails() { // given let temp_path = RandomTempPath::create_dir(); let key = VaultKey::new("password1", 1024); @@ -323,7 +349,7 @@ mod test { vault_file_path.push(VAULT_FILE_NAME); // when - let result = check_vault_file(&dir, &key); + let result = read_vault_file(&dir, &key); // then assert!(result.is_err()); @@ -336,7 +362,7 @@ mod test { } // when - let result = check_vault_file(&dir, &key); + let result = read_vault_file(&dir, &key); // then assert!(result.is_err()); @@ -392,4 +418,22 @@ mod test { // then assert!(vault.is_err()); } + + #[test] + fn vault_directory_can_preserve_meta() { + // given + let temp_path = RandomTempPath::new(); + let key = VaultKey::new("password", 1024); + let dir: PathBuf = temp_path.as_path().into(); + let vault = VaultDiskDirectory::create(&dir, "vault", key.clone()).unwrap(); + + // then + assert_eq!(vault.meta(), "{}".to_owned()); + assert!(vault.set_meta("Hello, world!!!").is_ok()); + assert_eq!(vault.meta(), "Hello, world!!!".to_owned()); + + // and when + let vault = VaultDiskDirectory::at(&dir, "vault", key.clone()).unwrap(); + assert_eq!(vault.meta(), "Hello, world!!!".to_owned()); + } } diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 01ff5004d..9b8a3d52a 100755 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -107,6 +107,14 @@ impl SimpleSecretStore for EthStore { fn change_account_vault(&self, vault: SecretVaultRef, account: StoreAccountRef) -> Result { self.store.change_account_vault(vault, account) } + + fn get_vault_meta(&self, name: &str) -> Result { + self.store.get_vault_meta(name) + } + + fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> { + self.store.set_vault_meta(name, meta) + } } impl SecretStore for EthStore { @@ -491,6 +499,20 @@ impl SimpleSecretStore for EthMultiStore { self.reload_accounts()?; Ok(new_account_ref) } + + fn get_vault_meta(&self, name: &str) -> Result { + self.vaults.lock() + .get(name) + .ok_or(Error::VaultNotFound) + .and_then(|v| Ok(v.meta())) + } + + fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> { + self.vaults.lock() + .get(name) + .ok_or(Error::VaultNotFound) + .and_then(|v| v.set_meta(meta)) + } } #[cfg(test)] diff --git a/ethstore/src/json/vault_file.rs b/ethstore/src/json/vault_file.rs index 4249a4fa8..eb7440a85 100755 --- a/ethstore/src/json/vault_file.rs +++ b/ethstore/src/json/vault_file.rs @@ -25,10 +25,13 @@ use super::Crypto; pub struct VaultFile { /// Vault password, encrypted with vault password pub crypto: Crypto, + /// Vault metadata string + pub meta: Option, } enum VaultFileField { Crypto, + Meta, } impl Deserialize for VaultFileField { @@ -49,6 +52,7 @@ impl Visitor for VaultFileFieldVisitor { { match value { "crypto" => Ok(VaultFileField::Crypto), + "meta" => Ok(VaultFileField::Meta), _ => Err(Error::custom(format!("Unknown field: '{}'", value))), } } @@ -58,7 +62,7 @@ impl Deserialize for VaultFile { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - static FIELDS: &'static [&'static str] = &["crypto"]; + static FIELDS: &'static [&'static str] = &["crypto", "meta"]; deserializer.deserialize_struct("VaultFile", FIELDS, VaultFileVisitor) } } @@ -72,11 +76,13 @@ impl Visitor for VaultFileVisitor { where V: MapVisitor { let mut crypto = None; + let mut meta = None; loop { match visitor.visit_key()? { - Some(VaultFileField::Crypto) => { crypto = Some(visitor.visit_value()?); } - None => { break; } + Some(VaultFileField::Crypto) => { crypto = Some(visitor.visit_value()?); }, + Some(VaultFileField::Meta) => { meta = Some(visitor.visit_value()?); } + None => { break; }, } } @@ -89,6 +95,7 @@ impl Visitor for VaultFileVisitor { let result = VaultFile { crypto: crypto, + meta: meta, }; Ok(result) @@ -125,7 +132,8 @@ mod test { salt: "b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5".into(), }), mac: "16381463ea11c6eb2239a9f339c2e780516d29d234ce30ac5f166f9080b5a262".into(), - } + }, + meta: Some("{}".into()), }; let serialized = serde_json::to_string(&file).unwrap(); diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs index 57cba259e..442c48a1d 100755 --- a/ethstore/src/secret_store.rs +++ b/ethstore/src/secret_store.rs @@ -65,6 +65,10 @@ pub trait SimpleSecretStore: Send + Sync { fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error>; /// Cnage account' vault fn change_account_vault(&self, vault: SecretVaultRef, account: StoreAccountRef) -> Result; + /// Get vault metadata string. + fn get_vault_meta(&self, name: &str) -> Result; + /// Set vault metadata string. + fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error>; } pub trait SecretStore: SimpleSecretStore { diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index 000e3c9eb..16dbae64f 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -248,6 +248,19 @@ impl ParityAccounts for ParityAccountsClient { .map_err(|e| errors::account("Could not change vault.", e)) .map(|_| true) } + + fn get_vault_meta(&self, name: String) -> Result { + take_weak!(self.accounts) + .get_vault_meta(&name) + .map_err(|e| errors::account("Could not get vault metadata.", e)) + } + + fn set_vault_meta(&self, name: String, meta: String) -> Result { + take_weak!(self.accounts) + .set_vault_meta(&name, &meta) + .map_err(|e| errors::account("Could not update vault metadata.", e)) + .map(|_| true) + } } fn into_vec(a: Vec) -> Vec where diff --git a/rpc/src/v1/tests/mocked/parity_accounts.rs b/rpc/src/v1/tests/mocked/parity_accounts.rs index 3f329ca2b..ad0ead9c0 100644 --- a/rpc/src/v1/tests/mocked/parity_accounts.rs +++ b/rpc/src/v1/tests/mocked/parity_accounts.rs @@ -351,3 +351,27 @@ fn rpc_parity_list_opened_vaults() { assert!(actual_response == Some(response1.to_owned()) || actual_response == Some(response2.to_owned())); } + +#[test] +fn rpc_parity_get_set_vault_meta() { + let temp_path = RandomTempPath::new(); + let tester = setup_with_vaults_support(temp_path.as_str()); + + assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); + assert!(tester.accounts.set_vault_meta("vault1", "vault1_meta").is_ok()); + + let request = r#"{"jsonrpc": "2.0", "method": "parity_getVaultMeta", "params":["vault1"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"vault1_meta","id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); + + let request = r#"{"jsonrpc": "2.0", "method": "parity_setVaultMeta", "params":["vault1", "updated_vault1_meta"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); + + let request = r#"{"jsonrpc": "2.0", "method": "parity_getVaultMeta", "params":["vault1"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"updated_vault1_meta","id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/traits/parity_accounts.rs b/rpc/src/v1/traits/parity_accounts.rs index c8c37964d..72aeeaa95 100644 --- a/rpc/src/v1/traits/parity_accounts.rs +++ b/rpc/src/v1/traits/parity_accounts.rs @@ -133,5 +133,13 @@ build_rpc_trait! { /// Change vault of the given address. #[rpc(name = "parity_changeVault")] fn change_vault(&self, H160, String) -> Result; + + /// Get vault metadata string. + #[rpc(name = "parity_getVaultMeta")] + fn get_vault_meta(&self, String) -> Result; + + /// Set vault metadata string. + #[rpc(name = "parity_setVaultMeta")] + fn set_vault_meta(&self, String, String) -> Result; } } From 0b3f97f79208cf64f52d624ca8d829d2b1e111c7 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 8 Feb 2017 14:38:27 +0100 Subject: [PATCH 11/13] Work with string numbers in contract (Fixes #4472) (#4478) --- js/src/ui/Form/TypedInput/typedInput.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/ui/Form/TypedInput/typedInput.js b/js/src/ui/Form/TypedInput/typedInput.js index 082777192..79365faeb 100644 --- a/js/src/ui/Form/TypedInput/typedInput.js +++ b/js/src/ui/Form/TypedInput/typedInput.js @@ -217,8 +217,8 @@ export default class TypedInput extends Component { renderEth () { const { ethValue, isEth } = this.state; - const value = ethValue && typeof ethValue.toNumber === 'function' - ? ethValue.toNumber() + const value = ethValue && typeof ethValue.toFixed === 'function' + ? ethValue.toFixed() // we need a string representation, could be >15 digits : ethValue; const input = isEth @@ -257,7 +257,7 @@ export default class TypedInput extends Component { return readOnly ? bnValue.toFormat() - : bnValue.toNumber(); + : bnValue.toFixed(); // we need a string representation, could be >15 digits } renderInteger (value = this.props.value, onChange = this.onChange) { From 68b872444029d7d7668a3651b347cd8665234d92 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Wed, 8 Feb 2017 13:49:08 +0000 Subject: [PATCH 12/13] [ci skip] js-precompiled 20170208-134350 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5556e1d0..8d2c20e43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1574,7 +1574,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#13f709d44a8634fccf121205d1b0976b9527d34a" +source = "git+https://github.com/ethcore/js-precompiled.git#cb0dd77b70c552bb68288a94c7d5d37ecdd611c8" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 9cb59d65f..634ffbc71 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.3.71", + "version": "0.3.72", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 877388953234b485a6751599650bc1578a6af76d Mon Sep 17 00:00:00 2001 From: "Denis S. Soldatov aka General-Beck" Date: Wed, 8 Feb 2017 22:06:09 +0400 Subject: [PATCH 13/13] downgrade rust (windows build) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 31f15c306..618764d5e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -422,7 +422,7 @@ windows: - set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64 - set RUST_BACKTRACE=1 - set RUSTFLAGS=%RUSTFLAGS% - - rustup default stable-x86_64-pc-windows-msvc + - rustup default 1.14.0-x86_64-pc-windows-msvc - cargo build --features final --release #%CARGOFLAGS% - signtool sign /f %keyfile% /p %certpass% target\release\parity.exe - target\release\parity.exe tools hash target\release\parity.exe > parity.sha3