Commit 674e3bf3 authored by Axel Chalon's avatar Axel Chalon Committed by Thibaut Sardan
Browse files

Parity Ethereum bundling (#458)



* Parity Ethereum bundling

* Grumbles; update light.js

* Grumbles

* Merge in PR#394 ac-upd-post: refactor sendStore post/postRaw

* Download highest version matching requirement rather than latest beta

* Rename RequireVersion to RequireParityVersion

* Grumbles

* Change Parity version requirement to ~2.4.1

* Fix --no-run-parity with Parity already running

* Grumble
Co-Authored-By: default avataraxelchalon <xaxel@protonmail.com>
parent 7e485f4f
Pipeline #33479 failed with stages
in 12 minutes and 30 seconds
......@@ -20,3 +20,7 @@ lib
# os-generated files
.DS_Store
# parity binary
packages/fether-electron/static/parity
packages/fether-electron/static/parity.exe
\ No newline at end of file
BSD 3-Clause License
Copyright (c) 2015-2018 Parity Technologies (UK) Ltd.
Copyright (c) 2015-2019 Parity Technologies (UK) Ltd.
All rights reserved.
Redistribution and use in source and binary forms, with or without
......
......@@ -40,6 +40,7 @@
"yarn": "^1.4.2"
},
"scripts": {
"postinstall": "cd scripts && node ./fetch-latest-parity.js",
"build": "lerna run build",
"preelectron": "yarn build",
"electron": "cd packages/fether-electron && yarn electron",
......@@ -66,5 +67,10 @@
"npm-run-all": "^4.1.2",
"prettier": "^1.14.2",
"semistandard": "^13.0.1"
},
"dependencies": {
"download": "^7.1.0",
"node-fetch": "^2.3.0",
"semver": "^5.6.0"
}
}
......@@ -25,7 +25,7 @@
],
"homepage": "https://github.com/paritytech/fether",
"parity": {
"channel": "stable"
"version": "~2.4.1"
},
"scripts": {
"prebuild": "copyfiles -u 2 \"../fether-react/build/**/*\" static/ && ./scripts/fixElectronBug.sh",
......@@ -39,7 +39,7 @@
"test": "jest --all --color --coverage"
},
"dependencies": {
"@parity/electron": "^4.0.0",
"@parity/electron": "^5.1.0",
"ansi-styles": "^3.2.1",
"commander": "^2.15.1",
"commander-remaining-args": "^1.2.0",
......
......@@ -6,6 +6,7 @@
import { checkClockSync, signerNewToken } from '@parity/electron';
import Pino from '../utils/pino';
import { bundledParityPath } from '../utils/paths';
const pino = Pino();
......@@ -32,7 +33,7 @@ export default async (fetherApp, event, action, ...args) => {
break;
}
case 'signer-new-token': {
const token = await signerNewToken();
const token = await signerNewToken({ parityPath: bundledParityPath });
// Send back the token to the renderer process
event.sender.send('signer-new-token-reply', token);
break;
......
......@@ -6,7 +6,7 @@
import ParityEthereum from '../parityEthereum';
function setupParityEthereum (fetherApp) {
// Download, install, and run Parity Ethereum if not running and requested
// Run Parity Ethereum if not running and requested
return new ParityEthereum(fetherApp.win);
}
......
......@@ -5,7 +5,7 @@
import path from 'path';
import staticPath from '../utils/staticPath';
import { staticPath } from '../utils/paths';
import Pino from '../utils/pino';
const iconBalloonPath = path.join(
......
......@@ -6,7 +6,7 @@
import path from 'path';
import url from 'url';
import staticPath from '../../utils/staticPath';
import { staticPath } from '../../utils/paths';
const INDEX_HTML_PATH =
process.env.ELECTRON_START_URL ||
......
......@@ -3,15 +3,10 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import {
getParityPath,
fetchParity,
isParityRunning,
runParity
} from '@parity/electron';
import { isParityRunning, runParity } from '@parity/electron';
import getRemainingArgs from 'commander-remaining-args';
import { parity } from '../../../../package.json';
import { bundledParityPath } from '../utils/paths';
import handleError from '../utils/handleError';
import cli from '../cli';
import Pino from '../utils/pino';
......@@ -26,29 +21,36 @@ class ParityEthereum {
throw new Error('Unable to initialise Parity Ethereum more than once');
}
// Check if Parity Ethereum is installed
getParityPath()
// Download and install Parity Ethereum if not present
.catch(() => {
pino.info('Downloading and Installing Parity Ethereum');
return this.install(fetherAppWindow);
})
.then(async () => {
// Do not run Parity Ethereum if the user ran Fether with --no-run-parity
if (!cli.runParity) {
return false;
}
/*
* - If an instance of Parity Ethereum is already running, we connect to it
* and then check in fether-react if the parity_versionInfo RPC returns
* a compatible version; otherwise, we error out.
* - If no instance of Parity Ethereum is running, we run the bundled Parity
* Ethereum binary.
*
* `parity signer new-token` is run on the bundled binary in any case. We
* don't use the $PATH anymore.
*/
// Do not run Parity Ethereum if it is already running
if (await this.isRunning()) {
return true;
}
// Run the bundled Parity Ethereum if needed and wanted
return new Promise(async (resolve, reject) => {
// Parity Ethereum is already running: don't run the bundled binary
if (await this.isRunning()) {
resolve(true);
return;
}
// Run Parity Ethereum when installed
await this.run();
pino.info('Running Parity Ethereum');
return true;
})
// User ran Fether with --no-run-parity: don't run the bundled binary
if (!cli.runParity) {
resolve(false);
return;
}
// Parity Ethereum isn't running: run the bundled binary
await this.run();
pino.info('Running Parity Ethereum');
resolve(true);
})
.then(isRunning => {
// Notify the renderers
fetherAppWindow.webContents.send('parity-running', isRunning);
......@@ -57,19 +59,6 @@ class ParityEthereum {
.catch(handleError);
}
install = fetherAppWindow => {
return fetchParity(fetherAppWindow, {
onProgress: progress => {
// Notify the renderers on download progress
return fetherAppWindow.webContents.send(
'parity-download-progress',
progress
);
},
parityChannel: parity.channel
});
};
isRunning = async () => {
return isParityRunning({
wsInterface: cli.wsInterface,
......@@ -77,8 +66,10 @@ class ParityEthereum {
});
};
// Run the bundled Parity Ethereum binary
run = async () => {
return runParity({
parityPath: bundledParityPath,
flags: [
...getRemainingArgs(cli),
'--light',
......
......@@ -5,6 +5,8 @@
/* global __static */
import path from 'path';
const appIsPackaged = !process.defaultApp;
/**
......@@ -16,4 +18,12 @@ const staticPath = appIsPackaged
? __dirname.replace(/app\.asar$/, 'static')
: __static;
export default staticPath;
/**
* Get the path to the bundled Parity Ethereum binary.
*/
const bundledParityPath =
process.platform === 'win32'
? path.join(staticPath, 'parity.exe')
: path.join(staticPath, 'parity');
export { staticPath, bundledParityPath };
......@@ -35,11 +35,11 @@
},
"dependencies": {
"@craco/craco": "^3.3.1",
"@parity/abi": "^3.0.27",
"@parity/api": "^3.0.27",
"@parity/contracts": "^3.0.27",
"@parity/light.js": "^3.0.27",
"@parity/light.js-react": "^3.0.27",
"@parity/abi": "^5.1.1",
"@parity/api": "^5.1.1",
"@parity/contracts": "^5.1.1",
"@parity/light.js": "^5.1.1",
"@parity/light.js-react": "^5.1.1",
"@parity/qr-signer": "^0.3.2",
"bignumber.js": "^8.0.1",
"bip39": "^2.5.0",
......
......@@ -5,7 +5,7 @@
import React, { Component } from 'react';
import { AccountCard, Clickable, Header } from 'fether-ui';
import { chainId$, withoutLoading } from '@parity/light.js';
import { chainId$ } from '@parity/light.js';
import { inject, observer } from 'mobx-react';
import light from '@parity/light.js-react';
......@@ -17,7 +17,7 @@ import withAccountsInfo from '../../utils/withAccountsInfo';
@withAccountsInfo
@inject('createAccountStore', 'parityStore')
@light({
chainId: () => chainId$().pipe(withoutLoading())
chainId: () => chainId$()
})
@observer
class AccountsList extends Component {
......
......@@ -20,6 +20,7 @@ import { version } from '../../package.json';
import Accounts from '../Accounts';
import BackupAccount from '../BackupAccount';
import Onboarding from '../Onboarding';
import RequireParityVersion from '../RequireParityVersion';
import RequireHealthOverlay from '../RequireHealthOverlay';
import Send from '../Send';
import Tokens from '../Tokens';
......@@ -137,35 +138,37 @@ class App extends Component {
return (
<div className='content'>
<div className='window'>
<Modal
title='New version available'
description={newRelease ? `${newRelease.name} was released!` : ''}
visible={newRelease && !newRelease.ignore}
buttons={this.renderModalLinks()}
>
<Router>
<Switch>
{/* The next line is the homepage */}
<Redirect exact from='/' to='/accounts' />
<Route path='/accounts' component={Accounts} />
<Route path='/onboarding' component={Onboarding} />
<Route path='/tokens/:accountAddress' component={Tokens} />
<Route
path='/whitelist/:accountAddress'
component={Whitelist}
/>
<Route
path='/backup/:accountAddress'
component={BackupAccount}
/>
<Route
path='/send/:tokenAddress/from/:accountAddress'
component={Send}
/>
<Redirect from='*' to='/' />
</Switch>
</Router>
</Modal>
<RequireParityVersion>
<Modal
title='New version available'
description={newRelease ? `${newRelease.name} was released!` : ''}
visible={newRelease && !newRelease.ignore}
buttons={this.renderModalLinks()}
>
<Router>
<Switch>
{/* The next line is the homepage */}
<Redirect exact from='/' to='/accounts' />
<Route path='/accounts' component={Accounts} />
<Route path='/onboarding' component={Onboarding} />
<Route path='/tokens/:accountAddress' component={Tokens} />
<Route
path='/whitelist/:accountAddress'
component={Whitelist}
/>
<Route
path='/backup/:accountAddress'
component={BackupAccount}
/>
<Route
path='/send/:tokenAddress/from/:accountAddress'
component={Send}
/>
<Redirect from='*' to='/' />
</Switch>
</Router>
</Modal>
</RequireParityVersion>
</div>
</div>
);
......
......@@ -5,7 +5,7 @@
import React, { Component } from 'react';
import { branch } from 'recompose';
import { chainName$, withoutLoading } from '@parity/light.js';
import { chainName$ } from '@parity/light.js';
import light from '@parity/light.js-react';
import withHealth from '../utils/withHealth';
......@@ -18,7 +18,7 @@ import withHealth from '../utils/withHealth';
}) => good || syncing,
// Only call light.js chainName$ if we're syncing or good
light({
chainName: () => chainName$().pipe(withoutLoading())
chainName: () => chainName$()
})
)
class Health extends Component {
......@@ -44,7 +44,7 @@ class Health extends Component {
} = this.props;
if (status.good) {
return '-good';
} else if (status.downloading || status.launching || status.syncing) {
} else if (status.launching || status.syncing) {
return '-syncing';
} else {
return '-bad';
......@@ -57,11 +57,7 @@ class Health extends Component {
chainName
} = this.props;
if (status.downloading) {
return `Downloading Parity Ethereum (${
payload.downloading.syncPercentage
}%)`;
} else if (status.launching) {
if (status.launching) {
return 'Launching the node...';
} else if (!status.nodeConnected && !status.internet) {
return 'No internet. No node connected';
......@@ -69,6 +65,8 @@ class Health extends Component {
return 'Connecting to node...';
} else if (status.nodeConnected && !status.internet) {
return 'No internet. Connected to node';
} else if (status.launching) {
return 'Launching the node...';
} else if (!status.clockSync) {
return 'Clock of host not in sync';
} else if (!status.peers) {
......
......@@ -6,7 +6,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { branch } from 'recompose';
import { chainName$, withoutLoading } from '@parity/light.js';
import { chainName$ } from '@parity/light.js';
import light from '@parity/light.js-react';
import { Modal } from 'fether-ui';
......@@ -22,7 +22,7 @@ import loading from '../../assets/img/icons/loading.svg';
}) => syncing,
// Only call light.js chainName$ if we're syncing
light({
chainName: () => chainName$().pipe(withoutLoading())
chainName: () => chainName$()
})
)
class HealthModal extends Component {
......@@ -55,9 +55,7 @@ class HealthModal extends Component {
health: { status }
} = this.props;
if (status.downloading) {
return 'Downloading Parity Ethereum...';
} else if (status.launching) {
if (status.launching) {
return 'Launching the node...';
} else if (!status.nodeConnected && !status.internet) {
return 'No internet. No node connected';
......@@ -84,10 +82,6 @@ class HealthModal extends Component {
if (!status.internet) {
return 'Please connect to the Internet';
} else if (status.downloading) {
return `Downloading Parity Ethereum... (${
payload.downloading.syncPercentage
}%)`;
} else if (!status.clockSync) {
return `Mac: System Preferences -> Date & Time -> Uncheck and recheck "Set date and time automatically"
Windows: Control Panel -> "Clock, Language, and Region" -> "Date and Time" -> Uncheck and recheck "Set date and time automatically"`;
......
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
// SPDX-License-Identifier: BSD-3-Clause
import React, { Component } from 'react';
import light from '@parity/light.js-react';
import { Modal } from 'fether-ui';
import { startWith, catchError } from 'rxjs/operators';
import { versionInfo$ } from '@parity/light.js';
import { of } from 'rxjs';
import semver from 'semver';
import { parity } from 'fether/package.json';
const requiredVersion = parity.version;
@light({
versionInfo: props =>
versionInfo$().pipe(
startWith(undefined),
catchError(e => {
/*
* parity_versionInfo was implemented on the LC with Parity v2.4.1
* If the RPC errors out, it means we're using Parity < v2.4.1
* Checking the version of Parity Ethereum in Fether was first released
* (Fether v0.3) along with a feature (#394) that requires Parity
* Ethereum >= v2.4.0
* Fether v0.3 should theoretically work with v2.4.0, but since there is
* no way to check for this exact version, we made Fether v0.3 require
* >= v2.4.1 (which we can check).
*
* If the RPC errors out, we're using Parity < v2.4.1 and Fether v0.3
* is "officially" not compatible with this version.
*/
return of({ version: { major: 0, minor: 0, patch: 0 } });
})
)
})
class RequireParityVersion extends Component {
render () {
const { versionInfo } = this.props;
if (versionInfo) {
const { major, minor, patch } = versionInfo.version;
if (!semver.satisfies(`${major}.${minor}.${patch}`, requiredVersion)) {
const friendlyVersion =
major === 0 && minor === 0 && patch === 0
? '<2.4.1'
: `${major}.${minor}.${patch}`;
return (
<Modal
title='Unsupported version'
description={`You are running Parity Ethereum ${friendlyVersion}, which is unsupported. Please use Parity Ethereum ${requiredVersion}`}
visible
/>
);
}
}
return this.props.children;
}
}
export default RequireParityVersion;
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
// SPDX-License-Identifier: BSD-3-Clause
import RequireParityVersion from './RequireParityVersion';
export default RequireParityVersion;
......@@ -6,7 +6,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { inject, observer } from 'mobx-react';
import { chainName$, withoutLoading } from '@parity/light.js';
import { chainName$ } from '@parity/light.js';
import light from '@parity/light.js-react';
import { withProps } from 'recompose';
import { Modal } from 'fether-ui';
......@@ -21,7 +21,7 @@ import { blockscoutTxUrl } from '../../utils/blockscout';
const MIN_CONFIRMATIONS = 6;
@light({
chainName: () => chainName$().pipe(withoutLoading())
chainName: () => chainName$()
})
@inject('sendStore')
@withTokens
......
......@@ -7,7 +7,7 @@ import React, { Component } from 'react';
import BigNumber from 'bignumber.js';
import { Clickable, Form as FetherForm, Header } from 'fether-ui';
import createDecorator from 'final-form-calculate';
import { chainId$, withoutLoading } from '@parity/light.js';
import { chainId$ } from '@parity/light.js';
import debounce from 'debounce-promise';
import { Field, Form } from 'react-final-form';
import { fromWei, toWei } from '@parity/api/lib/util/wei';
......@@ -38,7 +38,7 @@ const MIN_GAS_PRICE = 3; // Safelow gas price from GasStation, in Gwei
}))
@withAccount
@light({
chainId: () => chainId$().pipe(withoutLoading())
chainId: () => chainId$()
})
@withBalance // Balance of current token (can be ETH)
@withEthBalance // ETH balance
......
......@@ -35,7 +35,10 @@ class Unlock extends Component {
.send(values.password)
.then(() => history.push(`/send/${token.address}/from/${address}/sent`))
.catch(error => ({
password: error.text
password:
error.text === 'Method not found'
? "Please enable the 'personal' api in the --ws-apis launch flag of Parity Ethereum."
: error.text
}));
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment