Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Chain-selection from UI #4859

Merged
merged 22 commits into from
Mar 13, 2017
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
description = "Parity Ethereum client"
name = "parity"
version = "1.6.0"
version = "1.7.0"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]

Expand Down
52 changes: 44 additions & 8 deletions ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,9 @@ pub struct Client {
factories: Factories,
history: u64,
rng: Mutex<OsRng>,
on_mode_change: Mutex<Option<Box<FnMut(&Mode) + 'static + Send>>>,
on_user_defaults_change: Mutex<Option<Box<FnMut(Option<Mode>) + 'static + Send>>>,
registrar: Mutex<Option<Registry>>,
exit_handler: Mutex<Option<Box<Fn(bool, Option<String>) + 'static + Send>>>,
}

impl Client {
Expand Down Expand Up @@ -240,8 +241,9 @@ impl Client {
factories: factories,
history: history,
rng: Mutex::new(OsRng::new().map_err(::util::UtilError::StdIo)?),
on_mode_change: Mutex::new(None),
on_user_defaults_change: Mutex::new(None),
registrar: Mutex::new(None),
exit_handler: Mutex::new(None),
});

{
Expand Down Expand Up @@ -276,6 +278,25 @@ impl Client {
self.notify.write().push(Arc::downgrade(&target));
}

/// Set a closure to call when we want to restart the client
pub fn set_exit_handler<F>(&self, f: F) where F: Fn(bool, Option<String>) + 'static + Send {
*self.exit_handler.lock() = Some(Box::new(f));
}

/// Hypervisor should restart this client.
pub fn restart(&self) {
if let Some(ref h) = *self.exit_handler.lock() {
(*h)(true, None);
}
}

/// Hypervisor should kill this client.
pub fn exit(&self) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this called from? Why not just implement Drop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exit and restart are not yet called from anywhere, however, they seem like useful public api to have; i plan on implementing a UI endpoints for them to all the user to kill or restart parity easily.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how it belongs in Client, whose role is just to manage and provide blockchain data. Hypervisor stuff being at a higher level would make it a lot simpler to manage different kinds of clients, parity-as-a-library, non-hypervised instances, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will remove for the present PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess we might want to look into an alternative "hypervisor" IPC endpoint that could host such calls, however in the context of the present PR that would be too much extra baggage.

if let Some(ref h) = *self.exit_handler.lock() {
(*h)(false, None);
}
}

/// Returns engine reference.
pub fn engine(&self) -> &Engine {
&*self.engine
Expand All @@ -294,9 +315,9 @@ impl Client {
self.registrar.lock()
}

/// Register an action to be done if a mode change happens.
pub fn on_mode_change<F>(&self, f: F) where F: 'static + FnMut(&Mode) + Send {
*self.on_mode_change.lock() = Some(Box::new(f));
/// Register an action to be done if a mode/spec_name change happens.
pub fn on_user_defaults_change<F>(&self, f: F) where F: 'static + FnMut(Option<Mode>) + Send {
*self.on_user_defaults_change.lock() = Some(Box::new(f));
}

/// Flush the block import queue.
Expand Down Expand Up @@ -651,7 +672,6 @@ impl Client {
self.miner.clone()
}


/// Replace io channel. Useful for testing.
pub fn set_io_channel(&self, io_channel: IoChannel<ClientIoMessage>) {
*self.io_channel.lock() = io_channel;
Expand Down Expand Up @@ -1030,9 +1050,9 @@ impl BlockChainClient for Client {
let mut mode = self.mode.lock();
*mode = new_mode.clone().into();
trace!(target: "mode", "Mode now {:?}", &*mode);
if let Some(ref mut f) = *self.on_mode_change.lock() {
if let Some(ref mut f) = *self.on_user_defaults_change.lock() {
trace!(target: "mode", "Making callback...");
f(&*mode)
f(Some((&*mode).clone()))
}
}
match new_mode {
Expand All @@ -1042,6 +1062,22 @@ impl BlockChainClient for Client {
}
}

fn spec_name(&self) -> String {
self.config.spec_name.clone()
}

fn set_spec_name(&self, new_spec_name: String) {
trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name);
if !self.enabled.load(AtomicOrdering::Relaxed) {
return;
}
if let Some(ref h) = *self.exit_handler.lock() {
(*h)(true, Some(new_spec_name));
} else {
warn!("Not hypervised; cannot change chain.");
}
}

fn best_block_header(&self) -> encoded::Header {
self.chain.read().best_block_header()
}
Expand Down
2 changes: 2 additions & 0 deletions ethcore/src/client/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ pub struct ClientConfig {
pub db_wal: bool,
/// Operating mode
pub mode: Mode,
/// The chain spec name
pub spec_name: String,
/// Type of block verifier used by client.
pub verifier_type: VerifierType,
/// State db cache-size.
Expand Down
4 changes: 4 additions & 0 deletions ethcore/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,10 @@ impl BlockChainClient for TestBlockChainClient {

fn set_mode(&self, _: Mode) { unimplemented!(); }

fn spec_name(&self) -> String { "foundation".into() }

fn set_spec_name(&self, _: String) { unimplemented!(); }

fn disable(&self) { unimplemented!(); }

fn pruning_info(&self) -> PruningInfo {
Expand Down
6 changes: 6 additions & 0 deletions ethcore/src/client/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ pub trait BlockChainClient : Sync + Send {
/// Set the mode.
fn set_mode(&self, mode: Mode);

/// Get the chain spec name.
fn spec_name(&self) -> String;

/// Set the chain via a spec name.
fn set_spec_name(&self, spec_name: String);

/// Disable the client from importing blocks. This cannot be undone in this session and indicates
/// that a subsystem has reason to believe this executable incapable of syncing the chain.
fn disable(&self);
Expand Down
13 changes: 12 additions & 1 deletion js/src/api/rpc/parity/parity.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,15 @@ export default class Parity {
.execute('parity_mode');
}

// DEPRECATED - use chain instead.
netChain () {
return this._transport
.execute('parity_netChain');
.execute('parity_chain');
}

chain () {
return this._transport
.execute('parity_chain');
}

netPeers () {
Expand Down Expand Up @@ -454,6 +460,11 @@ export default class Parity {
.execute('parity_setMode', mode);
}

setChain (specName) {
return this._transport
.execute('parity_setChain', specName);
}

setNewDappsAddresses (addresses) {
return this._transport
.execute('parity_setNewDappsAddresses', addresses ? inAddresses(addresses) : null);
Expand Down
2 changes: 1 addition & 1 deletion js/src/jsonrpc/interfaces/parity.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export default {
'2017-01-20 18:14:19 Configured for DevelopmentChain using InstantSeal engine',
'2017-01-20 18:14:19 Operating mode: active',
'2017-01-20 18:14:19 State DB configuration: fast',
'2017-01-20 18:14:19 Starting Parity/v1.6.0-unstable-2ae8b4c-20170120/x86_64-linux-gnu/rustc1.14.0'
'2017-01-20 18:14:19 Starting Parity/v1.7.0-unstable-2ae8b4c-20170120/x86_64-linux-gnu/rustc1.14.0'
]
}
},
Expand Down
105 changes: 100 additions & 5 deletions js/src/views/Settings/Parity/parity.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default class Parity extends Component {
features = FeaturesStore.get();

componentWillMount () {
this.store.loadChain();
return this.store.loadMode();
}

Expand All @@ -50,11 +51,12 @@ export default class Parity extends Component {
<div>
<FormattedMessage
id='settings.parity.overview_0'
defaultMessage='Control the Parity node settings and mode of operation via this interface.'
defaultMessage='Control the Parity node settings and nature of syncing via this interface.'
/>
</div>
</div>
<div className={ layout.details }>
{ this.renderChains() }
{ this.renderModes() }
<Features />
<LanguageSelector />
Expand All @@ -65,12 +67,12 @@ export default class Parity extends Component {
);
}

renderItem (mode, label) {
renderItem (name, label) {
return (
<MenuItem
key={ mode }
key={ name }
label={ label }
value={ mode }
value={ name }
>
{ label }
</MenuItem>
Expand Down Expand Up @@ -134,7 +136,7 @@ export default class Parity extends Component {
hint={
<FormattedMessage
id='settings.parity.modes.hint'
defaultMessage='the syning mode for the Parity node'
defaultMessage='the syncing mode for the Parity node'
/>
}
label={
Expand Down Expand Up @@ -182,7 +184,100 @@ export default class Parity extends Component {
);
}

renderChains () {
const { chain } = this.store;

return (
<Select
id='parityChainSelect'
hint={
<FormattedMessage
id='settings.parity.chains.hint'
defaultMessage='the chain for the Parity node to sync to'
/>
}
label={
<FormattedMessage
id='settings.parity.chains.label'
defaultMessage='chain/network to sync'
/>
}
onChange={ this.onChangeChain }
value={ chain }
>
{
this.renderItem('foundation', (
<FormattedMessage
id='settings.parity.chains.chain_foundation'
defaultMessage='Parity syncs to the Ethereum network launched by the Ethereum Foundation'
/>
))
}
{
this.renderItem('kovan', (
<FormattedMessage
id='settings.parity.chains.chain_kovan'
defaultMessage='Parity syncs to the Kovan test network'
/>
))
}
{
this.renderItem('olympic', (
<FormattedMessage
id='settings.parity.chains.chain_olympic'
defaultMessage='Parity syncs to the Olympic test network'
/>
))
}
{
this.renderItem('morden', (
<FormattedMessage
id='settings.parity.chains.cmorden_kovan'
defaultMessage='Parity syncs to Morden (Classic) test network'
/>
))
}
{
this.renderItem('ropsten', (
<FormattedMessage
id='settings.parity.chains.chain_ropsten'
defaultMessage='Parity syncs to the Ropsten test network'
/>
))
}
{
this.renderItem('classic', (
<FormattedMessage
id='settings.parity.chains.chain_classic'
defaultMessage='Parity syncs to the Ethereum Classic network'
/>
))
}
{
this.renderItem('expanse', (
<FormattedMessage
id='settings.parity.chains.chain_expanse'
defaultMessage='Parity syncs to the Expanse network'
/>
))
}
{
this.renderItem('dev', (
<FormattedMessage
id='settings.parity.chains.chain_dev'
defaultMessage='Parity uses a local development chain'
/>
))
}
</Select>
);
}

onChangeMode = (event, index, mode) => {
this.store.changeMode(mode || event.target.value);
}

onChangeChain = (event, index, chain) => {
this.store.changeChain(chain || event.target.value);
}
}
28 changes: 28 additions & 0 deletions js/src/views/Settings/Parity/parity.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ describe('views/Settings/Parity', () => {
beforeEach(() => {
render();
sinon.spy(instance.store, 'loadMode');
sinon.spy(instance.store, 'loadChain');
});

afterEach(() => {
instance.store.loadMode.restore();
instance.store.loadChain.restore();
});

it('renders defaults', () => {
Expand All @@ -56,6 +58,10 @@ describe('views/Settings/Parity', () => {
it('loads the mode in the store', () => {
expect(instance.store.loadMode).to.have.been.called;
});

it('loads the chain in the store', () => {
expect(instance.store.loadChain).to.have.been.called;
});
});

describe('components', () => {
Expand Down Expand Up @@ -94,5 +100,27 @@ describe('views/Settings/Parity', () => {
expect(instance.store.changeMode).to.have.been.calledWith('dark');
});
});

describe('chain selector', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blank line before.

let select;

beforeEach(() => {
select = component.find('Select[id="parityChainSelect"]');
sinon.spy(instance.store, 'changeChain');
});

afterEach(() => {
instance.store.changeChain.restore();
});

it('renders a chain selector', () => {
expect(select).to.have.length(1);
});

it('changes the chain on the store when changed', () => {
select.simulate('change', { target: { value: 'dark' } });
expect(instance.store.changeChain).to.have.been.calledWith('dark');
});
});
});
});
Loading