diff --git a/Cargo.lock b/Cargo.lock index cca8b014d..05d6312ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -298,7 +298,6 @@ dependencies = [ "ethcore-ipc 1.4.0", "ethcore-ipc-codegen 1.4.0", "ethcore-ipc-nano 1.4.0", - "ethcore-network 1.5.0", "ethcore-util 1.5.0", "ethjson 0.1.0", "ethkey 0.2.0", @@ -1272,7 +1271,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#57f5bf943f24cf761ba58c1bea35a845e0b12414" +source = "git+https://github.com/ethcore/js-precompiled.git#c3e0b5772f508d9261e8b10141edcad2e8212005" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 29afb2226..1c6ef92e3 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -304,6 +304,9 @@ impl SignedTransaction { /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => ((v - 1) % 2) as u8, _ => 4 } } + /// The `v` value that appears in the RLP. + pub fn original_v(&self) -> u64 { self.v } + /// The network ID, or `None` if this is a global transaction. pub fn network_id(&self) -> Option { match self.v { diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 14df0819c..adc93484c 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -53,6 +53,8 @@ pub struct Config { /// Maximum heap memory to use. /// When the limit is reached, is_full returns true. pub max_mem_use: usize, + /// Settings for the number of verifiers and adaptation strategy. + pub verifier_settings: VerifierSettings, } impl Default for Config { @@ -60,6 +62,26 @@ impl Default for Config { Config { max_queue_size: 30000, max_mem_use: 50 * 1024 * 1024, + verifier_settings: VerifierSettings::default(), + } + } +} + +/// Verifier settings. +#[derive(Debug, PartialEq, Clone)] +pub struct VerifierSettings { + /// Whether to scale amount of verifiers according to load. + // Todo: replace w/ strategy enum? + pub scale_verifiers: bool, + /// Beginning amount of verifiers. + pub num_verifiers: usize, +} + +impl Default for VerifierSettings { + fn default() -> Self { + VerifierSettings { + scale_verifiers: false, + num_verifiers: MAX_VERIFIERS, } } } @@ -114,6 +136,7 @@ pub struct VerificationQueue { ticks_since_adjustment: AtomicUsize, max_queue_size: usize, max_mem_use: usize, + scale_verifiers: bool, verifier_handles: Vec>, state: Arc<(Mutex, Condvar)>, } @@ -198,13 +221,16 @@ impl VerificationQueue { }); let empty = Arc::new(SCondvar::new()); let panic_handler = PanicHandler::new_in_arc(); + let scale_verifiers = config.verifier_settings.scale_verifiers; - let max_verifiers = min(::num_cpus::get(), MAX_VERIFIERS); - let default_amount = max(::num_cpus::get(), 3) - 2; - let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new())); + let num_cpus = ::num_cpus::get(); + let max_verifiers = min(num_cpus, MAX_VERIFIERS); + let default_amount = max(1, min(max_verifiers, config.verifier_settings.num_verifiers)); + let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new())); let mut verifier_handles = Vec::with_capacity(max_verifiers); debug!(target: "verification", "Allocating {} verifiers, {} initially active", max_verifiers, default_amount); + debug!(target: "verification", "Verifier auto-scaling {}", if scale_verifiers { "enabled" } else { "disabled" }); for i in 0..max_verifiers { debug!(target: "verification", "Adding verification thread #{}", i); @@ -248,6 +274,7 @@ impl VerificationQueue { ticks_since_adjustment: AtomicUsize::new(0), max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), + scale_verifiers: scale_verifiers, verifier_handles: verifier_handles, state: state, } @@ -597,6 +624,8 @@ impl VerificationQueue { self.processing.write().shrink_to_fit(); + if !self.scale_verifiers { return } + if self.ticks_since_adjustment.fetch_add(1, AtomicOrdering::SeqCst) + 1 >= READJUSTMENT_PERIOD { self.ticks_since_adjustment.store(0, AtomicOrdering::SeqCst); } else { @@ -675,10 +704,15 @@ mod tests { use error::*; use views::*; - fn get_test_queue() -> BlockQueue { + // create a test block queue. + // auto_scaling enables verifier adjustment. + fn get_test_queue(auto_scale: bool) -> BlockQueue { let spec = get_test_spec(); let engine = spec.engine; - BlockQueue::new(Config::default(), engine, IoChannel::disconnected(), true) + + let mut config = Config::default(); + config.verifier_settings.scale_verifiers = auto_scale; + BlockQueue::new(config, engine, IoChannel::disconnected(), true) } #[test] @@ -691,7 +725,7 @@ mod tests { #[test] fn can_import_blocks() { - let queue = get_test_queue(); + let queue = get_test_queue(false); if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { panic!("error importing block that is valid by definition({:?})", e); } @@ -699,7 +733,7 @@ mod tests { #[test] fn returns_error_for_duplicates() { - let queue = get_test_queue(); + let queue = get_test_queue(false); if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { panic!("error importing block that is valid by definition({:?})", e); } @@ -718,7 +752,7 @@ mod tests { #[test] fn returns_ok_for_drained_duplicates() { - let queue = get_test_queue(); + let queue = get_test_queue(false); let block = get_good_dummy_block(); let hash = BlockView::new(&block).header().hash().clone(); if let Err(e) = queue.import(Unverified::new(block)) { @@ -735,7 +769,7 @@ mod tests { #[test] fn returns_empty_once_finished() { - let queue = get_test_queue(); + let queue = get_test_queue(false); queue.import(Unverified::new(get_good_dummy_block())) .expect("error importing block that is valid by definition"); queue.flush(); @@ -763,7 +797,7 @@ mod tests { fn scaling_limits() { use super::MAX_VERIFIERS; - let queue = get_test_queue(); + let queue = get_test_queue(true); queue.scale_verifiers(MAX_VERIFIERS + 1); assert!(queue.num_verifiers() < MAX_VERIFIERS + 1); @@ -775,7 +809,7 @@ mod tests { #[test] fn readjust_verifiers() { - let queue = get_test_queue(); + let queue = get_test_queue(true); // put all the verifiers to sleep to ensure // the test isn't timing sensitive. diff --git a/js/package.json b/js/package.json index 6f984d901..d09b100b0 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.94", + "version": "0.2.96", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", diff --git a/js/src/api/contract/contract.js b/js/src/api/contract/contract.js index d9ec9b03e..ed922a02c 100644 --- a/js/src/api/contract/contract.js +++ b/js/src/api/contract/contract.js @@ -189,15 +189,21 @@ export default class Contract { }); } - _encodeOptions (func, options, values) { + getCallData = (func, options, values) => { + let data = options.data; + const tokens = func ? this._abi.encodeTokens(func.inputParamTypes(), values) : null; const call = tokens ? func.encodeCall(tokens) : null; - if (options.data && options.data.substr(0, 2) === '0x') { - options.data = options.data.substr(2); + if (data && data.substr(0, 2) === '0x') { + data = data.substr(2); } - options.data = `0x${options.data || ''}${call || ''}`; + return `0x${data || ''}${call || ''}`; + } + + _encodeOptions (func, options, values) { + options.data = this.getCallData(func, options, values); return options; } @@ -209,10 +215,10 @@ export default class Contract { _bindFunction = (func) => { func.call = (options, values = []) => { - const callData = this._encodeOptions(func, this._addOptionsTo(options), values); + const callParams = this._encodeOptions(func, this._addOptionsTo(options), values); return this._api.eth - .call(callData) + .call(callParams) .then((encoded) => func.decodeOutput(encoded)) .then((tokens) => tokens.map((token) => token.value)) .then((returns) => returns.length === 1 ? returns[0] : returns); diff --git a/js/src/dapps/registry/Records/records.js b/js/src/dapps/registry/Records/records.js index 89c751c36..4837290a3 100644 --- a/js/src/dapps/registry/Records/records.js +++ b/js/src/dapps/registry/Records/records.js @@ -1,3 +1,19 @@ +// Copyright 2015, 2016 Ethcore (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, { Component, PropTypes } from 'react'; import { Card, CardHeader, CardText } from 'material-ui/Card'; import TextField from 'material-ui/TextField'; diff --git a/js/src/modals/CreateWallet/WalletDetails/walletDetails.js b/js/src/modals/CreateWallet/WalletDetails/walletDetails.js index 9126fdb72..5d581b81d 100644 --- a/js/src/modals/CreateWallet/WalletDetails/walletDetails.js +++ b/js/src/modals/CreateWallet/WalletDetails/walletDetails.js @@ -16,18 +16,62 @@ import React, { Component, PropTypes } from 'react'; -import { Form, TypedInput, Input, AddressSelect } from '../../../ui'; -import { parseAbiType } from '../../../util/abi'; +import { Form, TypedInput, Input, AddressSelect, InputAddress } from '~/ui'; +import { parseAbiType } from '~/util/abi'; + +import styles from '../createWallet.css'; export default class WalletDetails extends Component { static propTypes = { accounts: PropTypes.object.isRequired, wallet: PropTypes.object.isRequired, errors: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired + onChange: PropTypes.func.isRequired, + walletType: PropTypes.string.isRequired }; render () { + const { walletType } = this.props; + + if (walletType === 'WATCH') { + return this.renderWatchDetails(); + } + + return this.renderMultisigDetails(); + } + + renderWatchDetails () { + const { wallet, errors } = this.props; + + return ( +
+ + + + + + + ); + } + + renderMultisigDetails () { const { accounts, wallet, errors } = this.props; return ( @@ -64,27 +108,34 @@ export default class WalletDetails extends Component { param={ parseAbiType('address[]') } /> - +
+ - + +
); } + onAddressChange = (_, address) => { + this.props.onChange({ address }); + } + onAccoutChange = (_, account) => { this.props.onChange({ account }); } diff --git a/js/src/modals/CreateWallet/WalletInfo/walletInfo.js b/js/src/modals/CreateWallet/WalletInfo/walletInfo.js index 301263314..344f4e09a 100644 --- a/js/src/modals/CreateWallet/WalletInfo/walletInfo.js +++ b/js/src/modals/CreateWallet/WalletInfo/walletInfo.js @@ -16,7 +16,7 @@ import React, { Component, PropTypes } from 'react'; -import { CompletedStep, IdentityIcon, CopyToClipboard } from '../../../ui'; +import { CompletedStep, IdentityIcon, CopyToClipboard } from '~/ui'; import styles from '../createWallet.css'; @@ -34,15 +34,21 @@ export default class WalletInfo extends Component { daylimit: PropTypes.oneOfType([ PropTypes.string, PropTypes.number - ]).isRequired + ]).isRequired, + + deployed: PropTypes.bool }; render () { - const { address, required, daylimit, name } = this.props; + const { address, required, daylimit, name, deployed } = this.props; return ( -
{ name } has been deployed at
+
+ { name } + has been + { deployed ? 'deployed' : 'added' } at +
@@ -63,9 +69,9 @@ export default class WalletInfo extends Component { } renderOwners () { - const { account, owners } = this.props; + const { account, owners, deployed } = this.props; - return [].concat(account, owners).map((address, id) => ( + return [].concat(deployed ? account : null, owners).filter((a) => a).map((address, id) => (
{ this.addressToString(address) }
diff --git a/js/src/modals/CreateWallet/WalletType/index.js b/js/src/modals/CreateWallet/WalletType/index.js new file mode 100644 index 000000000..525e35495 --- /dev/null +++ b/js/src/modals/CreateWallet/WalletType/index.js @@ -0,0 +1,17 @@ +// Copyright 2015, 2016 Ethcore (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 './walletType.js'; diff --git a/js/src/modals/CreateWallet/WalletType/walletType.js b/js/src/modals/CreateWallet/WalletType/walletType.js new file mode 100644 index 000000000..e77d58fc6 --- /dev/null +++ b/js/src/modals/CreateWallet/WalletType/walletType.js @@ -0,0 +1,58 @@ +// Copyright 2015, 2016 Ethcore (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, { Component, PropTypes } from 'react'; + +import { RadioButtons } from '~/ui'; + +// import styles from '../createWallet.css'; + +export default class WalletType extends Component { + static propTypes = { + onChange: PropTypes.func.isRequired, + type: PropTypes.string.isRequired + }; + + render () { + const { type } = this.props; + + return ( + + ); + } + + getTypes () { + return [ + { + label: 'Multi-Sig wallet', key: 'MULTISIG', + description: 'A standard multi-signature Wallet' + }, + { + label: 'Watch a wallet', key: 'WATCH', + description: 'Add an existing wallet to your accounts' + } + ]; + } + + onTypeChange = (type) => { + this.props.onChange(type.key); + } +} diff --git a/js/src/modals/CreateWallet/createWallet.css b/js/src/modals/CreateWallet/createWallet.css index a450466f0..01c079260 100644 --- a/js/src/modals/CreateWallet/createWallet.css +++ b/js/src/modals/CreateWallet/createWallet.css @@ -37,3 +37,22 @@ height: 24px; } } + +.splitInput { + display: flex; + flex-direction: row; + + > * { + flex: 1; + + margin: 0 0.25em; + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + } +} diff --git a/js/src/modals/CreateWallet/createWallet.js b/js/src/modals/CreateWallet/createWallet.js index 8f38fec12..d99ef05b4 100644 --- a/js/src/modals/CreateWallet/createWallet.js +++ b/js/src/modals/CreateWallet/createWallet.js @@ -21,8 +21,9 @@ import ActionDone from 'material-ui/svg-icons/action/done'; import ContentClear from 'material-ui/svg-icons/content/clear'; import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward'; -import { Button, Modal, TxHash, BusyStep } from '../../ui'; +import { Button, Modal, TxHash, BusyStep } from '~/ui'; +import WalletType from './WalletType'; import WalletDetails from './WalletDetails'; import WalletInfo from './WalletInfo'; import CreateWalletStore from './createWalletStore'; @@ -64,7 +65,7 @@ export default class CreateWallet extends Component { visible actions={ this.renderDialogActions() } current={ stage } - steps={ steps } + steps={ steps.map((s) => s.title) } waiting={ waiting } > { this.renderPage() } @@ -98,24 +99,35 @@ export default class CreateWallet extends Component { required={ this.store.wallet.required } daylimit={ this.store.wallet.daylimit } name={ this.store.wallet.name } + + deployed={ this.store.deployed } /> ); - default: case 'DETAILS': return ( ); + + default: + case 'TYPE': + return ( + + ); } } renderDialogActions () { - const { step, hasErrors, rejected, onCreate } = this.store; + const { step, hasErrors, rejected, onCreate, onNext, onAdd } = this.store; const cancelBtn = (