From e7abd3510a7d7581f2d12a860766bd596550b946 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 19 May 2017 16:51:15 +0200 Subject: [PATCH 01/11] Use babel-runtime as opposed to babel-polyfill (#5662) * Add babel-runtime * Add babel-transform-runtime plugin * Remove babel-polyfill imports * Remove babel-polyfill package * Transform exports to work around webpack 2.2 --- js/.babelrc | 3 ++- js/package.json | 3 ++- js/src/embed.js | 1 - js/src/index.js | 1 - js/src/library.etherscan.js | 1 - js/src/library.shapeshift.js | 1 - js/src/parity.js | 1 - js/webpack/npm.js | 3 --- js/webpack/vendor.js | 1 - 9 files changed, 4 insertions(+), 11 deletions(-) diff --git a/js/.babelrc b/js/.babelrc index 5087af80d..127abf143 100644 --- a/js/.babelrc +++ b/js/.babelrc @@ -7,6 +7,8 @@ "transform-decorators-legacy", "transform-class-properties", "transform-object-rest-spread", + "transform-es2015-modules-commonjs", + "transform-runtime", "lodash", "recharts" ], @@ -25,7 +27,6 @@ }, "test": { "plugins": [ - "transform-runtime", [ "babel-plugin-webpack-alias", { "config": "webpack/test.js" } ] ] } diff --git a/js/package.json b/js/package.json index e2a3841d5..5c203a091 100644 --- a/js/package.json +++ b/js/package.json @@ -77,11 +77,11 @@ "babel-plugin-recharts": "1.1.0", "babel-plugin-transform-class-properties": "6.23.0", "babel-plugin-transform-decorators-legacy": "1.3.4", + "babel-plugin-transform-es2015-modules-commonjs": "6.24.1", "babel-plugin-transform-object-rest-spread": "6.23.0", "babel-plugin-transform-react-remove-prop-types": "0.3.2", "babel-plugin-transform-runtime": "6.23.0", "babel-plugin-webpack-alias": "2.1.2", - "babel-polyfill": "6.23.0", "babel-preset-env": "1.1.9", "babel-preset-es2015": "6.22.0", "babel-preset-es2016": "6.22.0", @@ -159,6 +159,7 @@ }, "dependencies": { "@parity/wordlist": "1.0.1", + "babel-runtime": "6.23.0", "base32.js": "0.1.0", "bignumber.js": "3.0.1", "blockies": "0.0.2", diff --git a/js/src/embed.js b/js/src/embed.js index 75cb5e45a..218bb2f4f 100644 --- a/js/src/embed.js +++ b/js/src/embed.js @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import 'babel-polyfill'; import 'whatwg-fetch'; import es6Promise from 'es6-promise'; diff --git a/js/src/index.js b/js/src/index.js index d1f9ac580..1436f30c0 100644 --- a/js/src/index.js +++ b/js/src/index.js @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import 'babel-polyfill'; import 'whatwg-fetch'; import es6Promise from 'es6-promise'; diff --git a/js/src/library.etherscan.js b/js/src/library.etherscan.js index c4cd9e5f9..1884822e6 100644 --- a/js/src/library.etherscan.js +++ b/js/src/library.etherscan.js @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import 'babel-polyfill/dist/polyfill.js'; import es6Promise from 'es6-promise'; es6Promise.polyfill(); diff --git a/js/src/library.shapeshift.js b/js/src/library.shapeshift.js index ab4b5dedd..6f6f4ccff 100644 --- a/js/src/library.shapeshift.js +++ b/js/src/library.shapeshift.js @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import 'babel-polyfill/dist/polyfill.js'; import es6Promise from 'es6-promise'; es6Promise.polyfill(); diff --git a/js/src/parity.js b/js/src/parity.js index 2305e22a0..9d414f90e 100644 --- a/js/src/parity.js +++ b/js/src/parity.js @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import 'babel-polyfill'; import 'whatwg-fetch'; import es6Promise from 'es6-promise'; diff --git a/js/webpack/npm.js b/js/webpack/npm.js index 2230bf90f..34b91467b 100644 --- a/js/webpack/npm.js +++ b/js/webpack/npm.js @@ -53,9 +53,6 @@ module.exports = { 'node-fetch': 'node-fetch' }, module: { - noParse: [ - /babel-polyfill/ - ], rules: [ { test: /(\.jsx|\.js)$/, diff --git a/js/webpack/vendor.js b/js/webpack/vendor.js index 5081a894f..3270c319c 100644 --- a/js/webpack/vendor.js +++ b/js/webpack/vendor.js @@ -23,7 +23,6 @@ const ENV = process.env.NODE_ENV || 'development'; const DEST = process.env.BUILD_DEST || '.build'; let modules = [ - 'babel-polyfill', 'bignumber.js', 'blockies', 'brace', From 3ff72794e515cb7159078721650fa9a987a92c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 19 May 2017 17:06:36 +0200 Subject: [PATCH 02/11] Create an account for chain=dev (#5612) * implement From<&'static str> for Secret * Dev account. * Fix Secret semantics. --- ethcore/src/blockchain/blockchain.rs | 2 +- ethcore/src/engines/authority_round.rs | 11 ++++---- ethcore/src/engines/basic_authority.rs | 5 ++-- ethcore/src/engines/tendermint/message.rs | 3 +-- ethcore/src/engines/tendermint/mod.rs | 3 +-- ethcore/src/engines/validator_set/contract.rs | 3 +-- ethcore/src/engines/validator_set/multi.rs | 4 +-- .../engines/validator_set/safe_contract.rs | 4 +-- ethcore/src/state/mod.rs | 2 +- ethcore/src/tests/client.rs | 4 +-- ethcore/src/types/transaction.rs | 2 +- ethcrypto/src/lib.rs | 2 +- ethkey/src/brain.rs | 2 +- ethkey/src/extended.rs | 7 +++-- ethkey/src/keypair.rs | 2 +- ethkey/src/secret.rs | 27 +++++++++++++++---- ethstore/src/account/crypto.rs | 2 +- ethstore/src/presale.rs | 2 +- parity/configuration.rs | 2 +- parity/run.rs | 23 ++++++++++++++++ rpc/src/v1/impls/parity_accounts.rs | 2 +- rpc/src/v1/impls/secretstore.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/tests/mocked/signing.rs | 2 +- .../key_server_cluster/decryption_session.rs | 2 +- test.sh | 4 +++ util/network/src/host.rs | 2 +- 27 files changed, 83 insertions(+), 45 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 631369e87..2690564e5 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1564,7 +1564,7 @@ mod tests { } fn secret() -> Secret { - Secret::from_slice(&"".sha3()).unwrap() + "".sha3().into() } #[test] diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 75a8d58a9..7c4fa6e7d 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -463,7 +463,6 @@ mod tests { use util::*; use header::Header; use error::{Error, BlockError}; - use ethkey::Secret; use rlp::encode; use block::*; use tests::helpers::*; @@ -513,8 +512,8 @@ mod tests { #[test] fn generates_seal_and_does_not_double_propose() { let tap = Arc::new(AccountProvider::transient_provider()); - let addr1 = tap.insert_account(Secret::from_slice(&"1".sha3()).unwrap(), "1").unwrap(); - let addr2 = tap.insert_account(Secret::from_slice(&"2".sha3()).unwrap(), "2").unwrap(); + let addr1 = tap.insert_account("1".sha3().into(), "1").unwrap(); + let addr2 = tap.insert_account("2".sha3().into(), "2").unwrap(); let spec = Spec::new_test_round(); let engine = &*spec.engine; @@ -545,7 +544,7 @@ mod tests { #[test] fn proposer_switching() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap(); + let addr = tap.insert_account("0".sha3().into(), "0").unwrap(); let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&0usize).to_vec()]); parent_header.set_gas_limit(U256::from_str("222222").unwrap()); @@ -570,7 +569,7 @@ mod tests { #[test] fn rejects_future_block() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap(); + let addr = tap.insert_account("0".sha3().into(), "0").unwrap(); let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&0usize).to_vec()]); @@ -596,7 +595,7 @@ mod tests { #[test] fn rejects_step_backwards() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap(); + let addr = tap.insert_account("0".sha3().into(), "0").unwrap(); let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&4usize).to_vec()]); diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 81a734f04..008a63424 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -229,7 +229,6 @@ mod tests { use error::{BlockError, Error}; use tests::helpers::*; use account_provider::AccountProvider; - use ethkey::Secret; use header::Header; use spec::Spec; use engines::Seal; @@ -281,7 +280,7 @@ mod tests { #[test] fn can_generate_seal() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(Secret::from_slice(&"".sha3()).unwrap(), "").unwrap(); + let addr = tap.insert_account("".sha3().into(), "").unwrap(); let spec = new_test_authority(); let engine = &*spec.engine; @@ -299,7 +298,7 @@ mod tests { #[test] fn seals_internally() { let tap = AccountProvider::transient_provider(); - let authority = tap.insert_account(Secret::from_slice(&"".sha3()).unwrap(), "").unwrap(); + let authority = tap.insert_account("".sha3().into(), "").unwrap(); let engine = new_test_authority().engine; assert!(!engine.seals_internally().unwrap()); diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index 304aa2671..8c2b44325 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -200,7 +200,6 @@ pub fn message_hash(vote_step: VoteStep, block_hash: H256) -> H256 { mod tests { use util::*; use rlp::*; - use ethkey::Secret; use account_provider::AccountProvider; use header::Header; use super::super::Step; @@ -250,7 +249,7 @@ mod tests { #[test] fn generate_and_verify() { let tap = Arc::new(AccountProvider::transient_provider()); - let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap(); + let addr = tap.insert_account("0".sha3().into(), "0").unwrap(); tap.unlock_account_permanently(addr, "0".into()).unwrap(); let mi = message_info_rlp(&VoteStep::new(123, 2, Step::Precommit), Some(H256::default())); diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 137f70a7a..782b9c56c 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -659,7 +659,6 @@ mod tests { use block::*; use error::{Error, BlockError}; use header::Header; - use ethkey::Secret; use client::chain_notify::ChainNotify; use miner::MinerService; use tests::helpers::*; @@ -708,7 +707,7 @@ mod tests { } fn insert_and_unlock(tap: &Arc, acc: &str) -> Address { - let addr = tap.insert_account(Secret::from_slice(&acc.sha3()).unwrap(), acc).unwrap(); + let addr = tap.insert_account(acc.sha3().into(), acc).unwrap(); tap.unlock_account_permanently(addr, acc.into()).unwrap(); addr } diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index dd4623023..b3c06aed1 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -116,7 +116,6 @@ impl ValidatorSet for ValidatorContract { mod tests { use util::*; use rlp::encode; - use ethkey::Secret; use spec::Spec; use header::Header; use account_provider::AccountProvider; @@ -140,7 +139,7 @@ mod tests { #[test] fn reports_validators() { let tap = Arc::new(AccountProvider::transient_provider()); - let v1 = tap.insert_account(Secret::from_slice(&"1".sha3()).unwrap(), "").unwrap(); + let v1 = tap.insert_account("1".sha3().into(), "").unwrap(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone())); client.engine().register_client(Arc::downgrade(&client)); let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap(); diff --git a/ethcore/src/engines/validator_set/multi.rs b/ethcore/src/engines/validator_set/multi.rs index c16a3424f..27570ed27 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -166,9 +166,9 @@ mod tests { fn uses_current_set() { ::env_logger::init().unwrap(); let tap = Arc::new(AccountProvider::transient_provider()); - let s0 = Secret::from_slice(&"0".sha3()).unwrap(); + let s0: Secret = "0".sha3().into(); let v0 = tap.insert_account(s0.clone(), "").unwrap(); - let v1 = tap.insert_account(Secret::from_slice(&"1".sha3()).unwrap(), "").unwrap(); + let v1 = tap.insert_account("1".sha3().into(), "").unwrap(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_multi, Some(tap)); client.engine().register_client(Arc::downgrade(&client)); diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 262aa0def..27415418e 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -294,9 +294,9 @@ mod tests { #[test] fn knows_validators() { let tap = Arc::new(AccountProvider::transient_provider()); - let s0 = Secret::from_slice(&"1".sha3()).unwrap(); + let s0: Secret = "1".sha3().into(); let v0 = tap.insert_account(s0.clone(), "").unwrap(); - let v1 = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "").unwrap(); + let v1 = tap.insert_account("0".sha3().into(), "").unwrap(); let network_id = Spec::new_validator_safe_contract().network_id(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap)); client.engine().register_client(Arc::downgrade(&client)); diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 90055f275..384c0cca9 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -962,7 +962,7 @@ mod tests { use types::executed::CallType; fn secret() -> Secret { - Secret::from_slice(&"".sha3()).unwrap() + "".sha3().into() } #[test] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 02db15617..b86c84a07 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -27,7 +27,7 @@ use devtools::*; use miner::Miner; use spec::Spec; use views::BlockView; -use ethkey::{KeyPair, Secret}; +use ethkey::KeyPair; use transaction::{PendingTransaction, Transaction, Action, Condition}; use miner::MinerService; @@ -296,7 +296,7 @@ fn change_history_size() { #[test] fn does_not_propagate_delayed_transactions() { - let key = KeyPair::from_secret(Secret::from_slice(&"test".sha3()).unwrap()).unwrap(); + let key = KeyPair::from_secret("test".sha3().into()).unwrap(); let secret = key.secret(); let tx0 = PendingTransaction::new(Transaction { nonce: 0.into(), diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 2c35400a8..2b17cee25 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -113,7 +113,7 @@ impl HeapSizeOf for Transaction { impl From for SignedTransaction { fn from(t: ethjson::state::Transaction) -> Self { let to: Option = t.to.into(); - let secret = t.secret.map(|s| Secret::from_slice(&s.0).expect("Valid secret expected.")); + let secret = t.secret.map(|s| Secret::from_slice(&s.0)); let tx = Transaction { nonce: t.nonce.into(), gas_price: t.gas_price.into(), diff --git a/ethcrypto/src/lib.rs b/ethcrypto/src/lib.rs index 4f14cf4d9..209162bba 100644 --- a/ethcrypto/src/lib.rs +++ b/ethcrypto/src/lib.rs @@ -192,7 +192,7 @@ pub mod ecdh { let sec = key::SecretKey::from_slice(context, &secret)?; let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); - Secret::from_slice(&shared[0..32]) + Secret::from_unsafe_slice(&shared[0..32]) .map_err(|_| Error::Secp(SecpError::InvalidSecretKey)) } } diff --git a/ethkey/src/brain.rs b/ethkey/src/brain.rs index cf675a843..9976bdb01 100644 --- a/ethkey/src/brain.rs +++ b/ethkey/src/brain.rs @@ -38,7 +38,7 @@ impl Generator for Brain { match i > 16384 { false => i += 1, true => { - if let Ok(secret) = Secret::from_slice(&secret) { + if let Ok(secret) = Secret::from_unsafe_slice(&secret) { let result = KeyPair::from_secret(secret); if result.as_ref().ok().map_or(false, |r| r.address()[0] == 0) { return result; diff --git a/ethkey/src/extended.rs b/ethkey/src/extended.rs index 77b35f774..7df6fde1c 100644 --- a/ethkey/src/extended.rs +++ b/ethkey/src/extended.rs @@ -99,8 +99,7 @@ impl ExtendedSecret { pub fn derive(&self, index: Derivation) -> ExtendedSecret where T: Label { let (derived_key, next_chain_code) = derivation::private(*self.secret, self.chain_code, index); - let derived_secret = Secret::from_slice(&*derived_key) - .expect("Derivation always produced a valid private key; qed"); + let derived_secret = Secret::from_slice(&*derived_key); ExtendedSecret::with_code(derived_secret, next_chain_code) } @@ -181,7 +180,7 @@ impl ExtendedKeyPair { pub fn with_seed(seed: &[u8]) -> Result { let (master_key, chain_code) = derivation::seed_pair(seed); Ok(ExtendedKeyPair::with_secret( - Secret::from_slice(&*master_key).map_err(|_| DerivationError::InvalidSeed)?, + Secret::from_unsafe_slice(&*master_key).map_err(|_| DerivationError::InvalidSeed)?, chain_code, )) } @@ -402,7 +401,7 @@ mod tests { fn test_extended(f: F, test_private: H256) where F: Fn(ExtendedSecret) -> ExtendedSecret { let (private_seed, chain_code) = master_chain_basic(); - let extended_secret = ExtendedSecret::with_code(Secret::from_slice(&*private_seed).unwrap(), chain_code); + let extended_secret = ExtendedSecret::with_code(Secret::from_slice(&*private_seed), chain_code); let derived = f(extended_secret); assert_eq!(**derived.as_raw(), test_private); } diff --git a/ethkey/src/keypair.rs b/ethkey/src/keypair.rs index 58747e172..8975063d5 100644 --- a/ethkey/src/keypair.rs +++ b/ethkey/src/keypair.rs @@ -62,7 +62,7 @@ impl KeyPair { } pub fn from_secret_slice(slice: &[u8]) -> Result { - Self::from_secret(Secret::from_slice(slice)?) + Self::from_secret(Secret::from_unsafe_slice(slice)?) } pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self { diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index e1c5bd2fa..de35d6b04 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -33,7 +33,7 @@ impl fmt::Debug for Secret { } impl Secret { - fn from_slice_unchecked(key: &[u8]) -> Self { + pub fn from_slice(key: &[u8]) -> Self { assert_eq!(32, key.len(), "Caller should provide 32-byte length slice"); let mut h = H256::default(); @@ -41,11 +41,17 @@ impl Secret { Secret { inner: h } } - pub fn from_slice(key: &[u8]) -> Result { + /// Imports and validates the key. + pub fn from_unsafe_slice(key: &[u8]) -> Result { let secret = key::SecretKey::from_slice(&super::SECP256K1, key)?; Ok(secret.into()) } + /// Checks validity of this key. + pub fn check_validity(&self) -> Result<(), Error> { + self.to_secp256k1_secret().map(|_| ()) + } + /// Inplace add one secret key to another (scalar + scalar) pub fn add(&mut self, other: &Secret) -> Result<(), Error> { let mut key_secret = self.to_secp256k1_secret()?; @@ -121,14 +127,25 @@ impl Secret { impl FromStr for Secret { type Err = Error; fn from_str(s: &str) -> Result { - let hash = H256::from_str(s).map_err(|e| Error::Custom(format!("{:?}", e)))?; - Self::from_slice(&hash) + Ok(H256::from_str(s).map_err(|e| Error::Custom(format!("{:?}", e)))?.into()) + } +} + +impl From for Secret { + fn from(s: H256) -> Self { + Secret::from_slice(&s) + } +} + +impl From<&'static str> for Secret { + fn from(s: &'static str) -> Self { + s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s)) } } impl From for Secret { fn from(key: key::SecretKey) -> Self { - Self::from_slice_unchecked(&key[0..32]) + Self::from_slice(&key[0..32]) } } diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs index 343e44cb4..9d1530429 100755 --- a/ethstore/src/account/crypto.rs +++ b/ethstore/src/account/crypto.rs @@ -122,7 +122,7 @@ impl Crypto { } let secret = self.do_decrypt(password, 32)?; - Ok(Secret::from_slice(&secret)?) + Ok(Secret::from_unsafe_slice(&secret)?) } /// Try to decrypt and return result as is diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index dbbdcdc8d..0c3e72e31 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -50,7 +50,7 @@ impl PresaleWallet { let len = crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)?; let unpadded = &key[..len]; - let secret = Secret::from_slice(&unpadded.keccak256())?; + let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?; if let Ok(kp) = KeyPair::from_secret(secret) { if kp.address() == self.address { return Ok(kp) diff --git a/parity/configuration.rs b/parity/configuration.rs index 9aa0d9753..bfed67aa1 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -695,7 +695,7 @@ impl Configuration { ret.listen_address = listen.map(|l| format!("{}", l)); ret.public_address = public.map(|p| format!("{}", p)); ret.use_secret = match self.args.flag_node_key.as_ref() - .map(|s| s.parse::().or_else(|_| Secret::from_slice(&s.sha3())).map_err(|e| format!("Invalid key: {:?}", e)) + .map(|s| s.parse::().or_else(|_| Secret::from_unsafe_slice(&s.sha3())).map_err(|e| format!("Invalid key: {:?}", e)) ) { None => None, Some(Ok(key)) => Some(key), diff --git a/parity/run.rs b/parity/run.rs index 20b553541..0f45e585c 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -30,6 +30,7 @@ use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions}; use ethcore::snapshot; use ethcore::verification::queue::VerifierSettings; +use ethcore::ethstore::ethkey; use light::Cache as LightDataCache; use ethsync::SyncConfig; use informant::Informant; @@ -820,9 +821,31 @@ fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, } } + // Add development account if running dev chain: + if let SpecType::Dev = *spec { + insert_dev_account(&account_provider); + } + Ok(account_provider) } +fn insert_dev_account(account_provider: &AccountProvider) { + let secret: ethkey::Secret = "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into(); + let dev_account = ethkey::KeyPair::from_secret(secret.clone()).expect("Valid secret produces valid key;qed"); + if let Ok(false) = account_provider.has_account(dev_account.address()) { + match account_provider.insert_account(secret, "") { + Err(e) => warn!("Unable to add development account: {}", e), + Ok(address) => { + let _ = account_provider.set_account_name(address.clone(), "Development Account".into()); + let _ = account_provider.set_account_meta(address, ::serde_json::to_string(&(vec![ + ("description", "Never use this account outside of develoopment chain!"), + ("passwordHint","Password is empty string"), + ].into_iter().collect::<::std::collections::HashMap<_,_>>())).expect("Serialization of hashmap does not fail.")); + }, + } + } +} + // Construct an error `String` with an adaptive hint on how to create an account. fn build_create_account_hint(spec: &SpecType, keys: &str) -> String { format!("You can create an account via RPC, UI or `parity account new --chain {} --keys-path {}`.", spec, keys) diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index cc206696f..5ee153db5 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -93,7 +93,7 @@ impl ParityAccounts for ParityAccountsClient { fn new_account_from_secret(&self, secret: RpcH256, pass: String) -> Result { let store = self.account_provider()?; - let secret = Secret::from_slice(&secret.0) + let secret = Secret::from_unsafe_slice(&secret.0) .map_err(|e| errors::account("Could not create account.", e))?; store.insert_account(secret, &pass) .map(Into::into) diff --git a/rpc/src/v1/impls/secretstore.rs b/rpc/src/v1/impls/secretstore.rs index bf09baeb6..570e12760 100644 --- a/rpc/src/v1/impls/secretstore.rs +++ b/rpc/src/v1/impls/secretstore.rs @@ -58,7 +58,7 @@ impl SecretStoreClient { /// Decrypt secret key using account' private key fn decrypt_secret(&self, address: H160, password: String, key: Bytes) -> Result { self.decrypt_key(address, password, key) - .and_then(|s| Secret::from_slice(&s).map_err(|e| errors::account("invalid secret", e))) + .and_then(|s| Secret::from_unsafe_slice(&s).map_err(|e| errors::account("invalid secret", e))) } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 13840ba26..c446b1874 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -302,7 +302,7 @@ fn rpc_eth_submit_hashrate() { fn rpc_eth_sign() { let tester = EthTester::default(); - let account = tester.accounts_provider.insert_account(Secret::from_slice(&[69u8; 32]).unwrap(), "abcd").unwrap(); + let account = tester.accounts_provider.insert_account(Secret::from_slice(&[69u8; 32]), "abcd").unwrap(); tester.accounts_provider.unlock_account_permanently(account, "abcd".into()).unwrap(); let _message = "0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f".from_hex().unwrap(); diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index e86d5d487..8963286ea 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() { // given let tester = eth_signing(); let data = vec![5u8]; - let acc = tester.accounts.insert_account(Secret::from_slice(&[69u8; 32]).unwrap(), "test").unwrap(); + let acc = tester.accounts.insert_account(Secret::from_slice(&[69u8; 32]), "test").unwrap(); tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap(); // when diff --git a/secret_store/src/key_server_cluster/decryption_session.rs b/secret_store/src/key_server_cluster/decryption_session.rs index 8f5ecff7d..96361ef46 100644 --- a/secret_store/src/key_server_cluster/decryption_session.rs +++ b/secret_store/src/key_server_cluster/decryption_session.rs @@ -1089,7 +1089,7 @@ mod tests { use ethcrypto::DEFAULT_MAC; use ethcrypto::ecies::decrypt; let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter() - .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap()) + .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap())) .collect(); let decrypted_secret = math::decrypt_with_shadow_coefficients(decrypted_secret.decrypted_secret, decrypted_secret.common_point.unwrap(), decrypt_shadows).unwrap(); assert_eq!(decrypted_secret, SECRET_PLAIN.into()); diff --git a/test.sh b/test.sh index f5a636bab..bac95a766 100755 --- a/test.sh +++ b/test.sh @@ -13,6 +13,10 @@ case $1 in OPTIONS="" shift ;; + --no-run) + OPTIONS="--no-run" + shift + ;; *) # unknown option ;; diff --git a/util/network/src/host.rs b/util/network/src/host.rs index bb4b4fb1e..93cbce804 100644 --- a/util/network/src/host.rs +++ b/util/network/src/host.rs @@ -1242,7 +1242,7 @@ fn load_key(path: &Path) -> Option { fn key_save_load() { use ::devtools::RandomTempPath; let temp_path = RandomTempPath::create_dir(); - let key = Secret::from_slice(&H256::random()).unwrap(); + let key = H256::random().into(); save_key(temp_path.as_path(), &key); let r = load_key(temp_path.as_path()); assert_eq!(key, r.unwrap()); From 84cab181207f9289695d7e05ff54defb2165b415 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 19 May 2017 17:07:59 +0200 Subject: [PATCH 03/11] Update the Console dapp (#5602) * Init Console Dapp structure * Watches and status * First REPL and display * Attaching console * Selectable autocomplete * working console // Display objects nicely * Multilines in Console Dapps * Better UI * Eval on window object * Save console gistory * Adding views * Add settings to the console dapp * Add / remove Watches * Add Snippets Cmponent * Semi Working Snippets * Working Snippets * Adding CodeMirror features * Removing old Console * Add Static folder --- js/package.json | 2 + js/src/dapps/console.js | 59 ++ .../dapps/console/Application/application.css | 65 ++ .../dapps/console/Application/application.js | 94 +++ .../console/Application/application.store.js | 42 + js/src/dapps/console/Application/index.js | 17 + .../console/Autocomplete/autocomplete.css | 55 ++ .../console/Autocomplete/autocomplete.js | 96 +++ .../Autocomplete/autocomplete.store.js | 234 ++++++ js/src/dapps/console/Autocomplete/index.js | 17 + js/src/dapps/console/Console/console.css | 58 ++ js/src/dapps/console/Console/console.js | 118 +++ js/src/dapps/console/Console/console.store.js | 126 +++ js/src/dapps/console/Console/index.js | 17 + js/src/dapps/console/Header/header.css | 51 ++ js/src/dapps/console/Header/header.js | 65 ++ js/src/dapps/console/Header/index.js | 17 + js/src/dapps/console/Input/index.js | 17 + js/src/dapps/console/Input/input.css | 46 ++ js/src/dapps/console/Input/input.js | 145 ++++ js/src/dapps/console/Input/input.store.js | 124 +++ js/src/dapps/console/Settings/index.js | 17 + js/src/dapps/console/Settings/settings.css | 32 + js/src/dapps/console/Settings/settings.js | 70 ++ .../dapps/console/Settings/settings.store.js | 71 ++ js/src/dapps/console/Snippets/index.js | 17 + js/src/dapps/console/Snippets/snippets.css | 122 +++ js/src/dapps/console/Snippets/snippets.js | 221 ++++++ .../dapps/console/Snippets/snippets.store.js | 249 ++++++ js/src/dapps/console/Watches/index.js | 17 + js/src/dapps/console/Watches/watches.css | 107 +++ js/src/dapps/console/Watches/watches.js | 186 +++++ js/src/dapps/console/Watches/watches.store.js | 148 ++++ js/src/dapps/console/codemirror.css | 36 + js/src/dapps/console/parity.js | 335 ++++++++ js/src/dapps/console/utils.js | 36 + js/src/dapps/static/.gitkeep | 0 js/src/dapps/static/console.css | 221 ------ js/src/dapps/static/console.html | 19 - js/src/dapps/static/console.js | 730 ------------------ js/src/dapps/style.css | 4 +- js/src/views/Dapps/builtin.json | 23 +- js/yarn.lock | 56 +- 43 files changed, 3189 insertions(+), 993 deletions(-) create mode 100644 js/src/dapps/console.js create mode 100644 js/src/dapps/console/Application/application.css create mode 100644 js/src/dapps/console/Application/application.js create mode 100644 js/src/dapps/console/Application/application.store.js create mode 100644 js/src/dapps/console/Application/index.js create mode 100644 js/src/dapps/console/Autocomplete/autocomplete.css create mode 100644 js/src/dapps/console/Autocomplete/autocomplete.js create mode 100644 js/src/dapps/console/Autocomplete/autocomplete.store.js create mode 100644 js/src/dapps/console/Autocomplete/index.js create mode 100644 js/src/dapps/console/Console/console.css create mode 100644 js/src/dapps/console/Console/console.js create mode 100644 js/src/dapps/console/Console/console.store.js create mode 100644 js/src/dapps/console/Console/index.js create mode 100644 js/src/dapps/console/Header/header.css create mode 100644 js/src/dapps/console/Header/header.js create mode 100644 js/src/dapps/console/Header/index.js create mode 100644 js/src/dapps/console/Input/index.js create mode 100644 js/src/dapps/console/Input/input.css create mode 100644 js/src/dapps/console/Input/input.js create mode 100644 js/src/dapps/console/Input/input.store.js create mode 100644 js/src/dapps/console/Settings/index.js create mode 100644 js/src/dapps/console/Settings/settings.css create mode 100644 js/src/dapps/console/Settings/settings.js create mode 100644 js/src/dapps/console/Settings/settings.store.js create mode 100644 js/src/dapps/console/Snippets/index.js create mode 100644 js/src/dapps/console/Snippets/snippets.css create mode 100644 js/src/dapps/console/Snippets/snippets.js create mode 100644 js/src/dapps/console/Snippets/snippets.store.js create mode 100644 js/src/dapps/console/Watches/index.js create mode 100644 js/src/dapps/console/Watches/watches.css create mode 100644 js/src/dapps/console/Watches/watches.js create mode 100644 js/src/dapps/console/Watches/watches.store.js create mode 100644 js/src/dapps/console/codemirror.css create mode 100644 js/src/dapps/console/parity.js create mode 100644 js/src/dapps/console/utils.js create mode 100644 js/src/dapps/static/.gitkeep delete mode 100755 js/src/dapps/static/console.css delete mode 100755 js/src/dapps/static/console.html delete mode 100755 js/src/dapps/static/console.js diff --git a/js/package.json b/js/package.json index 5c203a091..bcfe4f5d7 100644 --- a/js/package.json +++ b/js/package.json @@ -196,11 +196,13 @@ "react": "15.4.2", "react-ace": "4.1.0", "react-addons-css-transition-group": "15.4.2", + "react-codemirror": "^0.3.0", "react-copy-to-clipboard": "4.2.3", "react-dom": "15.4.2", "react-dropzone": "3.7.3", "react-element-to-jsx-string": "6.0.0", "react-event-listener": "0.4.1", + "react-inspector": "paritytech/react-inspector", "react-intl": "2.1.5", "react-markdown": "2.4.4", "react-portal": "3.0.0", diff --git a/js/src/dapps/console.js b/js/src/dapps/console.js new file mode 100644 index 000000000..44b6dcb9c --- /dev/null +++ b/js/src/dapps/console.js @@ -0,0 +1,59 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { AppContainer } from 'react-hot-loader'; + +import 'codemirror/addon/dialog/dialog'; +import 'codemirror/addon/dialog/dialog.css'; +import 'codemirror/addon/hint/javascript-hint'; +import 'codemirror/addon/hint/show-hint'; +import 'codemirror/addon/hint/show-hint.css'; +import 'codemirror/addon/search/match-highlighter'; +import 'codemirror/addon/search/search'; +import 'codemirror/addon/search/searchcursor'; +import 'codemirror/keymap/sublime'; +import 'codemirror/lib/codemirror.css'; +import 'codemirror/mode/javascript/javascript'; +// Custom codemirror style +import './console/codemirror.css'; + +import Application from './console/Application'; + +import '../../assets/fonts/Roboto/font.css'; +import '../../assets/fonts/RobotoMono/font.css'; +import './style.css'; + +ReactDOM.render( + + + , + document.querySelector('#container') +); + +if (module.hot) { + module.hot.accept('./console/Application/index.js', () => { + require('./console/Application/index.js'); + + ReactDOM.render( + + + , + document.querySelector('#container') + ); + }); +} diff --git a/js/src/dapps/console/Application/application.css b/js/src/dapps/console/Application/application.css new file mode 100644 index 000000000..eea2c030d --- /dev/null +++ b/js/src/dapps/console/Application/application.css @@ -0,0 +1,65 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.app { + display: flex; + flex-direction: column; + font-family: Arial, sans-serif; + font-size: 11px; + height: 100vh; + overflow: hidden; +} + +textarea, +input { + font-family: dejavu sans mono, monospace; + outline: none; +} + +code, +pre { + font-family: dejavu sans mono, monospace; + font-size: 11px; +} + +.header { + flex: 0 0 auto; +} + +.view { + display: flex; + flex: 1; + flex-direction: column; +} + +.eval { + flex: 0 1 auto; + font-family: dejavu sans mono, monospace; + overflow: auto; +} + +.input { + border-top: 1px solid #eee; + display: flex; + flex: 1 1 auto; + min-height: 50px; +} + +.status { + flex: 0 0 auto; + font-family: dejavu sans mono, monospace; +} diff --git a/js/src/dapps/console/Application/application.js b/js/src/dapps/console/Application/application.js new file mode 100644 index 000000000..5a591e710 --- /dev/null +++ b/js/src/dapps/console/Application/application.js @@ -0,0 +1,94 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { observer } from 'mobx-react'; +import React, { Component } from 'react'; + +import { api } from '../parity'; + +import Console from '../Console'; +import Header from '../Header'; +import Input from '../Input'; +import Settings from '../Settings'; +import Snippets from '../Snippets'; +import Watches from '../Watches'; + +import ApplicationStore from './application.store'; +import WatchesStore from '../Watches/watches.store'; + +import styles from './application.css'; + +@observer +export default class Application extends Component { + application = ApplicationStore.get(); + watches = WatchesStore.get(); + + componentWillMount () { + this.watches.add('time', () => new Date()); + this.watches.add('blockNumber', api.eth.blockNumber, api); + } + + render () { + return ( +
+
+
+
+ + { this.renderView() } + +
+ +
+
+ ); + } + + renderView () { + const { view } = this.application; + + if (view === 'console') { + return ( +
+
+ +
+
+ +
+
+ ); + } + + if (view === 'settings') { + return ( +
+ +
+ ); + } + + if (view === 'snippets') { + return ( +
+ +
+ ); + } + + return null; + } +} diff --git a/js/src/dapps/console/Application/application.store.js b/js/src/dapps/console/Application/application.store.js new file mode 100644 index 000000000..c10be46c6 --- /dev/null +++ b/js/src/dapps/console/Application/application.store.js @@ -0,0 +1,42 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { action, observable } from 'mobx'; + +let instance; + +export default class ApplicationStore { + @observable view = this.views[0].id; + + views = [ + { label: 'Console', id: 'console' }, + { label: 'Snippets', id: 'snippets' }, + { label: 'Settings', id: 'settings' } + ]; + + static get () { + if (!instance) { + instance = new ApplicationStore(); + } + + return instance; + } + + @action + setView (view) { + this.view = view; + } +} diff --git a/js/src/dapps/console/Application/index.js b/js/src/dapps/console/Application/index.js new file mode 100644 index 000000000..3d8d1ca3b --- /dev/null +++ b/js/src/dapps/console/Application/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './application'; diff --git a/js/src/dapps/console/Autocomplete/autocomplete.css b/js/src/dapps/console/Autocomplete/autocomplete.css new file mode 100644 index 000000000..8d4585e7a --- /dev/null +++ b/js/src/dapps/console/Autocomplete/autocomplete.css @@ -0,0 +1,55 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.container { + background: #f8f8f8; + box-shadow: 0 0.125em 0.25em rgba(0, 0, 0, 0.5); + font-family: dejavu sans mono, monospace; + left: 20px; + position: absolute; + max-height: 300px; + overflow: auto; +} + +.item { + background-color: white; + padding: 0.25em 0.25em 0.25em 0.35em; + display: flex; + justify-content: space-between; + + &.selected { + background-color: rgb(64, 115, 244); + + &, + .proto { + color: white; + } + } + + &:hover { + cursor: default; + } + + &:hover:not(.selected) { + background-color: rgb(230, 236, 255); + } + + .proto { + color: gray; + margin-left: 1em; + } +} diff --git a/js/src/dapps/console/Autocomplete/autocomplete.js b/js/src/dapps/console/Autocomplete/autocomplete.js new file mode 100644 index 000000000..e2938f23d --- /dev/null +++ b/js/src/dapps/console/Autocomplete/autocomplete.js @@ -0,0 +1,96 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { observer } from 'mobx-react'; +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; + +import AutocompleteStore from './autocomplete.store'; + +import styles from './autocomplete.css'; + +@observer +export default class Autocomplete extends Component { + autocompleteStore = AutocompleteStore.get(); + + render () { + if (!this.autocompleteStore.show) { + return null; + } + + return ( +
+ { this.renderAutocompletes() } +
+ ); + } + + renderAutocompletes () { + const { selected, values } = this.autocompleteStore; + const displayedProto = {}; + + return values.map((autocomplete, index) => { + const { name, prototypeName } = autocomplete; + const onClick = () => this.handleClick(index); + const setRef = (node) => this.setRef(index, node); + + const proto = !displayedProto[prototypeName] + ? ( + + { prototypeName } + + ) + : null; + + if (!displayedProto[prototypeName]) { + displayedProto[prototypeName] = true; + } + + const classes = [ styles.item ]; + + if (index === selected) { + classes.push(styles.selected); + } + + return ( +
+ + { name } + + { proto } +
+ ); + }); + } + + handleClick = (index) => { + this.autocompleteStore.select(index); + }; + + setRef = (index, node) => { + const element = ReactDOM.findDOMNode(node); + + this.autocompleteStore.setElement(index, element); + }; +} diff --git a/js/src/dapps/console/Autocomplete/autocomplete.store.js b/js/src/dapps/console/Autocomplete/autocomplete.store.js new file mode 100644 index 000000000..82ff2f24d --- /dev/null +++ b/js/src/dapps/console/Autocomplete/autocomplete.store.js @@ -0,0 +1,234 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { action, observable } from 'mobx'; + +import { evaluate } from '../utils'; + +let instance; + +export default class AutocompleteStore { + @observable values = []; + @observable position = {}; + @observable show = false; + @observable selected = null; + + elements = {}; + inputNode = null; + lastObject = null; + lastObjectPropertyNames = []; + + static get () { + if (!instance) { + instance = new AutocompleteStore(); + } + + return instance; + } + + get hasSelected () { + return this.selected !== null; + } + + clearCache () { + this.lastObject = null; + this.lastObjectPropertyNames = null; + } + + @action + focus (offset = 1) { + if (this.values.length === 0) { + this.selected = null; + return; + } + + this.selected = this.selected === null + ? ( + offset === 1 + ? 0 + : this.values.length - 1 + ) + : (this.values.length + this.selected + offset) % (this.values.length); + + if (this.isVisible(this.selected)) { + return; + } + + const element = this.elements[this.selected]; + + if (!element) { + return; + } + + element.scrollIntoView(offset === -1); + } + + focusOnInput () { + if (!this.inputNode) { + return; + } + + this.inputNode.focus(); + } + + @action + hide () { + this.show = false; + this.selected = null; + } + + isVisible (index) { + const element = this.elements[index]; + + if (!element) { + return false; + } + + const eBoundings = element.getBoundingClientRect(); + const pBoundings = element.parentElement.getBoundingClientRect(); + + if (eBoundings.top < pBoundings.top || eBoundings.bottom > pBoundings.bottom) { + return false; + } + + return true; + } + + select (inputStore, _index = this.selected) { + const index = _index === null + ? 0 + : _index; + + if (!this.values[index]) { + console.warn(`autocomplete::select has been called on AutocompleteStore with wrong value ${index}`); + return; + } + + const { name } = this.values[index]; + const { input } = inputStore; + const objects = input.split('.'); + + objects[objects.length - 1] = name; + const nextInput = objects.join('.'); + + this.hide(); + this.focusOnInput(); + return inputStore.updateInput(nextInput, false); + } + + setElement (index, element) { + this.elements[index] = element; + } + + setInputNode (node) { + this.inputNode = node; + } + + @action + setPosition () { + if (!this.inputNode) { + return; + } + + const inputBoundings = this.inputNode.getBoundingClientRect(); + const bodyBoundings = document.body.getBoundingClientRect(); + + // display on bottom of input + if (inputBoundings.top < bodyBoundings.height / 2) { + const nextPosition = { + top: 20 + }; + + this.position = nextPosition; + return; + } + + // display on top of input + const nextPosition = { + bottom: inputBoundings.height + }; + + this.position = nextPosition; + return; + } + + @action + setValues (values) { + this.values = values; + this.selected = null; + const show = values.length > 0; + + // Reveal autocomplete + if (!this.show && show) { + this.setPosition(); + } + + this.show = show; + } + + update (input) { + if (input.length === 0) { + return this.setValues([]); + } + + const objects = input.split('.'); + const suffix = objects.pop().toLowerCase(); + const prefix = objects.join('.'); + const object = prefix.length > 0 + ? prefix + : 'window'; + + if (object !== this.lastObject) { + const evalResult = evaluate(object); + + if (evalResult.error) { + this.lastObjectProperties = []; + } else { + this.lastObjectProperties = getAllProperties(evalResult.result); + } + + this.lastObject = object; + } + + const autocompletes = this.lastObjectProperties.filter((property) => { + return property.name.toLowerCase().includes(suffix); + }); + + return this.setValues(autocompletes); + } +} + +function getAllProperties (object) { + const propertyNames = {}; + + while (object) { + const prototypeName = object && object.constructor && object.constructor.name || ''; + + Object.getOwnPropertyNames(object) + .sort() + .forEach((name) => { + if (Object.prototype.hasOwnProperty.call(propertyNames, name)) { + return; + } + + propertyNames[name] = { name, prototypeName }; + }); + + object = Object.getPrototypeOf(object); + } + + return Object.values(propertyNames); +} diff --git a/js/src/dapps/console/Autocomplete/index.js b/js/src/dapps/console/Autocomplete/index.js new file mode 100644 index 000000000..5761be0e3 --- /dev/null +++ b/js/src/dapps/console/Autocomplete/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './autocomplete'; diff --git a/js/src/dapps/console/Console/console.css b/js/src/dapps/console/Console/console.css new file mode 100644 index 000000000..a0b3db4ff --- /dev/null +++ b/js/src/dapps/console/Console/console.css @@ -0,0 +1,58 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.result { + border-top: 1px solid #eee; + display: flex; + font-family: dejavu sans mono, monospace; + padding: 0.35em 0.25em; + + &.error { + background-color: hsl(0, 100%, 97%); + + .text { + color: red; + } + } + + &.warn { + background-color: hsl(50, 100%, 95%); + } +} + +.type { + font-weight: bold !important; + font-size: 8pt; + padding: 0 0.5em 0 0.25em; +} + +.time { + color: gray; + padding: 0 1em 0 0.5em; +} + +.token { + white-space: pre-wrap; +} + +.text { + display: flex; +} + +.text .token:not(:first-child) { + margin-left: 0.5em; +} diff --git a/js/src/dapps/console/Console/console.js b/js/src/dapps/console/Console/console.js new file mode 100644 index 000000000..75f9713a6 --- /dev/null +++ b/js/src/dapps/console/Console/console.js @@ -0,0 +1,118 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { observer } from 'mobx-react'; +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import { ObjectInspector } from 'react-inspector'; + +import ConsoleStore from './console.store'; +import SettingsStore from '../Settings/settings.store'; + +import styles from './console.css'; + +const ICONS = { + debug: ' ', + error: '✖', + info: 'ℹ', + input: '>', + log: ' ', + result: '<', + warn: '⚠' +}; + +@observer +export default class Console extends Component { + consoleStore = ConsoleStore.get(); + settingsStore = SettingsStore.get(); + + render () { + return ( +
+ { this.renderResults() } +
+ ); + } + + renderResults () { + const { logs } = this.consoleStore; + + return logs.map((data, index) => { + const { type, timestamp } = data; + const values = this.consoleStore.logValues[index]; + const classes = [ styles.result, styles[type] ]; + + return ( +
+ + { this.renderTimestamp(timestamp) } + + { + values.map((value, valueIndex) => ( + + { this.toString(value) } + + )) + } + +
+ ); + }); + } + + renderTimestamp (timestamp) { + const { displayTimestamps } = this.settingsStore; + + if (!displayTimestamps) { + return null; + } + + return ( + + { new Date(timestamp).toISOString().slice(11, 23) } + + ); + } + + setRef = (node) => { + const element = ReactDOM.findDOMNode(node); + + this.consoleStore.setNode(element); + }; + + toString (value) { + if (typeof value === 'string') { + return value; + } + + if (value instanceof Error) { + return value.toString(); + } + + return ( + + ); + } +} diff --git a/js/src/dapps/console/Console/console.store.js b/js/src/dapps/console/Console/console.store.js new file mode 100644 index 000000000..dc2fc6db4 --- /dev/null +++ b/js/src/dapps/console/Console/console.store.js @@ -0,0 +1,126 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { action, observable } from 'mobx'; + +import AutocompleteStore from '../Autocomplete/autocomplete.store'; +import { evaluate } from '../utils'; + +let instance; + +export default class ConsoleStore { + @observable logs = []; + + autocompleteStore = AutocompleteStore.get(); + logValues = []; + node = null; + + constructor () { + this.attachConsole(); + } + + static get () { + if (!instance) { + instance = new ConsoleStore(); + } + + return instance; + } + + attachConsole () { + ['debug', 'error', 'info', 'log', 'warn'].forEach((level) => { + const old = window.console[level].bind(window.console); + + window.console[level] = (...args) => { + old(...args); + this.log({ type: level, values: args }); + }; + }); + } + + @action + clear () { + this.logs = []; + this.logValues = []; + } + + evaluate (input) { + this.log({ type: 'input', value: input }); + + setTimeout(() => { + const { result, error } = evaluate(input); + let value = error || result; + const type = error + ? 'error' + : 'result'; + + if (typeof value === 'string') { + value = `"${value}"`; + } + + if (value && typeof value === 'object' && typeof value.then === 'function') { + return value + .then((result) => { + this.log({ type: 'result', value: result }); + }) + .catch((error) => { + this.log({ type: 'error', value: error }); + }); + } + + this.log({ type, value }); + }); + } + + @action + log ({ type, value, values }) { + this.logs.push({ + type, + timestamp: Date.now() + }); + + if (values) { + this.logValues.push(values); + } else { + this.logValues.push([ value ]); + } + + this.autocompleteStore.setPosition(); + this.scroll(); + } + + setNode (node) { + this.node = node; + this.scroll(); + } + + scroll () { + if (!this.node) { + return; + } + + setTimeout(() => { + if (this.node.children.length === 0) { + return; + } + + // Scroll to the last child + this.node + .children[this.node.children.length - 1] + .scrollIntoView(false); + }, 50); + } +} diff --git a/js/src/dapps/console/Console/index.js b/js/src/dapps/console/Console/index.js new file mode 100644 index 000000000..2956b330f --- /dev/null +++ b/js/src/dapps/console/Console/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './console'; diff --git a/js/src/dapps/console/Header/header.css b/js/src/dapps/console/Header/header.css new file mode 100644 index 000000000..116de6b8c --- /dev/null +++ b/js/src/dapps/console/Header/header.css @@ -0,0 +1,51 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.container { + background-color: #f3f3f3; + border-bottom: 1px solid #ccc; + font-size: 12px; + padding: 0 0.5em; +} + +.tabs { + display: flex; +} + +.tab { + align-items: center; + box-sizing: border-box; + border: 1px solid transparent; + color: #333; + cursor: default; + display: flex; + height: 24px; + line-height: 15px; + margin-top: 2px; + padding: 2px 6px 2px 4px; + + &:hover, + &.active:hover { + background-color: #e5e5e5; + } + + &.active { + background-color: white; + border: 1px solid #ccc; + border-bottom: none; + } +} diff --git a/js/src/dapps/console/Header/header.js b/js/src/dapps/console/Header/header.js new file mode 100644 index 000000000..c422b8256 --- /dev/null +++ b/js/src/dapps/console/Header/header.js @@ -0,0 +1,65 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { observer } from 'mobx-react'; +import React, { Component } from 'react'; + +import ApplicationStore from '../Application/application.store'; + +import styles from './header.css'; + +@observer +export default class Header extends Component { + application = ApplicationStore.get(); + + render () { + return ( +
+
+ { this.renderTabs() } +
+
+ ); + } + + renderTabs () { + const { view } = this.application; + + return this.application.views.map((tab) => { + const { label, id } = tab; + const classes = [ styles.tab ]; + const onClick = () => this.handleClickTab(id); + + if (id === view) { + classes.push(styles.active); + } + + return ( +
+ { label } +
+ ); + }); + } + + handleClickTab = (id) => { + this.application.setView(id); + }; +} diff --git a/js/src/dapps/console/Header/index.js b/js/src/dapps/console/Header/index.js new file mode 100644 index 000000000..aef90266f --- /dev/null +++ b/js/src/dapps/console/Header/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './header'; diff --git a/js/src/dapps/console/Input/index.js b/js/src/dapps/console/Input/index.js new file mode 100644 index 000000000..29e00f72b --- /dev/null +++ b/js/src/dapps/console/Input/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './input'; diff --git a/js/src/dapps/console/Input/input.css b/js/src/dapps/console/Input/input.css new file mode 100644 index 000000000..7b0c2306e --- /dev/null +++ b/js/src/dapps/console/Input/input.css @@ -0,0 +1,46 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.type { + color: #59f; + font-weight: bold !important; + font-size: 11px; + padding: 0 0.5em 0 0.25em; +} + +.inputContainer { + flex: 1; +} + +.input { + border: 0; + margin: 0; + padding: 0; + color: black; + height: 100%; + font-size: 11px; + resize: none; + width: 100%; +} + +.container { + border-top: 1px solid lightgray; + display: flex; + flex: 1; + padding: 0.25em; + position: relative; +} diff --git a/js/src/dapps/console/Input/input.js b/js/src/dapps/console/Input/input.js new file mode 100644 index 000000000..3263aff38 --- /dev/null +++ b/js/src/dapps/console/Input/input.js @@ -0,0 +1,145 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import keycode from 'keycode'; +import { observer } from 'mobx-react'; +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; + +import Autocomplete from '../Autocomplete'; + +import AutocompleteStore from '../Autocomplete/autocomplete.store'; +import ConsoleStore from '../Console/console.store'; +import InputStore from './input.store'; +import SettingsStore from '../Settings/settings.store'; + +import styles from './input.css'; + +@observer +export default class Input extends Component { + autocompleteStore = AutocompleteStore.get(); + consoleStore = ConsoleStore.get(); + inputStore = InputStore.get(); + settingsStore = SettingsStore.get(); + + render () { + const { input } = this.inputStore; + + return ( +
+ + > +
+