Better handling of Solidity compliation (#4860)
* Better use of SW * Safe-guard against pending SW register bug (in Chrome) * Added a simple Worker for Solidity compilation
This commit is contained in:
parent
1c37ea5860
commit
e73d867dab
@ -201,6 +201,7 @@
|
||||
"scryptsy": "2.0.0",
|
||||
"solc": "ngotchac/solc-js",
|
||||
"store": "1.3.20",
|
||||
"sw-toolbox": "^3.6.0",
|
||||
"u2f-api": "0.0.9",
|
||||
"u2f-api-polyfill": "0.4.3",
|
||||
"uglify-js": "2.8.2",
|
||||
@ -210,6 +211,7 @@
|
||||
"validator": "6.2.0",
|
||||
"web3": "0.17.0-beta",
|
||||
"whatwg-fetch": "2.0.1",
|
||||
"worker-loader": "^0.8.0",
|
||||
"zxcvbn": "4.4.1"
|
||||
}
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ contract multisig {
|
||||
|
||||
// TODO: document
|
||||
function execute(address _to, uint _value, bytes _data) external returns (bytes32 o_hash);
|
||||
function confirm(bytes32 _h) external returns (bool o_success);
|
||||
function confirm(bytes32 _h) returns (bool o_success);
|
||||
}
|
||||
|
||||
// usage:
|
||||
|
@ -16,15 +16,22 @@
|
||||
|
||||
import PromiseWorker from 'promise-worker';
|
||||
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
||||
import WebWorker from 'worker-loader!~/webWorker.js';
|
||||
|
||||
import { setWorker } from './workerActions';
|
||||
|
||||
function getWorker () {
|
||||
// Setup the Service Worker
|
||||
if ('serviceWorker' in navigator) {
|
||||
return runtime
|
||||
.register()
|
||||
.then(() => navigator.serviceWorker.ready)
|
||||
// Setup the Service Worker
|
||||
setupServiceWorker()
|
||||
.then(() => console.log('SW is setup'))
|
||||
.catch((error) => console.error('SW error', error));
|
||||
|
||||
function setupServiceWorker () {
|
||||
if (!('serviceWorker' in navigator)) {
|
||||
return Promise.reject('Service Worker is not available in your browser.');
|
||||
}
|
||||
|
||||
const getServiceWorker = () => {
|
||||
return navigator.serviceWorker.ready
|
||||
.then((registration) => {
|
||||
const worker = registration.active;
|
||||
|
||||
@ -32,9 +39,34 @@ function getWorker () {
|
||||
|
||||
return new PromiseWorker(worker);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.reject('Service Worker is not available in your browser.');
|
||||
return new Promise((resolve, reject) => {
|
||||
// Safe guard for registration bugs (happens in Chrome sometimes)
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
console.warn('could not register SW after 2.5s');
|
||||
getServiceWorker().then(resolve).catch(reject);
|
||||
}, 2500);
|
||||
|
||||
// Setup the Service Worker
|
||||
runtime
|
||||
.register()
|
||||
.then(() => {
|
||||
window.clearTimeout(timeoutId);
|
||||
return getServiceWorker();
|
||||
})
|
||||
.then(resolve).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
function getWorker () {
|
||||
try {
|
||||
const worker = new PromiseWorker(new WebWorker());
|
||||
|
||||
return Promise.resolve(worker);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
export const setupWorker = (store) => {
|
||||
@ -43,27 +75,16 @@ export const setupWorker = (store) => {
|
||||
const state = getState();
|
||||
const stateWorker = state.worker.worker;
|
||||
|
||||
if (stateWorker !== undefined && !(stateWorker && stateWorker._worker.state === 'redundant')) {
|
||||
if (stateWorker !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
getWorker()
|
||||
.then((worker) => {
|
||||
if (worker) {
|
||||
worker._worker.addEventListener('statechange', (event) => {
|
||||
console.warn('worker state changed to', worker._worker.state);
|
||||
|
||||
// Re-install the new Worker
|
||||
if (worker._worker.state === 'redundant') {
|
||||
setupWorker(store);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(setWorker(worker));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('sw', error);
|
||||
console.error('setupWorker', error);
|
||||
dispatch(setWorker(null));
|
||||
});
|
||||
};
|
||||
|
@ -14,15 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import registerPromiseWorker from 'promise-worker/register';
|
||||
import { Signer } from '~/util/signer';
|
||||
import SolidityUtils from '~/util/solidity';
|
||||
import toolbox from 'sw-toolbox';
|
||||
|
||||
const CACHE_NAME = 'parity-cache-v1';
|
||||
toolbox.precache(self.serviceWorkerOption.assets);
|
||||
|
||||
registerPromiseWorker((msg) => {
|
||||
return handleMessage(msg);
|
||||
});
|
||||
/**
|
||||
* Cache the SOLC files : if not available, make a network request
|
||||
*/
|
||||
toolbox.router.any(/raw.githubusercontent.com\/ethereum\/solc-bin(.+)list\.json$/, toolbox.cacheFirst);
|
||||
toolbox.router.any(/raw.githubusercontent.com\/ethereum\/solc-bin(.+)soljson(.+)\.js$/, toolbox.cacheFirst);
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(self.skipWaiting());
|
||||
@ -31,126 +31,3 @@ self.addEventListener('install', (event) => {
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(self.clients.claim());
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const { url } = event.request;
|
||||
|
||||
if (/raw.githubusercontent.com\/ethereum\/solc-bin(.+)list\.json$/.test(url)) {
|
||||
// Return the cached version, but still update it in background
|
||||
return event.respondWith(cachedFetcher(event.request, true));
|
||||
}
|
||||
|
||||
if (/raw.githubusercontent.com\/ethereum\/solc-bin(.+)soljson(.+)\.js$/.test(url)) {
|
||||
return event.respondWith(cachedFetcher(event.request));
|
||||
}
|
||||
});
|
||||
|
||||
self.solc = {};
|
||||
self.files = {};
|
||||
|
||||
function cachedFetcher (request, update = false) {
|
||||
return caches
|
||||
.match(request)
|
||||
.then((response) => {
|
||||
// Return cached response if exists and no
|
||||
// updates needed
|
||||
if (response && !update) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const fetcher = fetch(request.clone())
|
||||
.then((response) => {
|
||||
// Check if we received a valid response
|
||||
if (!response || response.status !== 200) {
|
||||
return response;
|
||||
}
|
||||
|
||||
return caches
|
||||
.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
cache.put(request, response.clone());
|
||||
return response;
|
||||
});
|
||||
});
|
||||
|
||||
// Cache hit - return response
|
||||
// Still want to perform the fetch (update)
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
return fetcher;
|
||||
});
|
||||
}
|
||||
|
||||
function handleMessage (message) {
|
||||
switch (message.action) {
|
||||
case 'compile':
|
||||
return compile(message.data);
|
||||
|
||||
case 'load':
|
||||
return getCompiler(message.data).then(() => 'ok');
|
||||
|
||||
case 'setFiles':
|
||||
return setFiles(message.data);
|
||||
|
||||
case 'getSignerSeed':
|
||||
return getSignerSeed(message.data);
|
||||
|
||||
default:
|
||||
console.warn(`unknown action "${message.action}"`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getSignerSeed (data) {
|
||||
console.log('deriving seed from service-worker');
|
||||
const { wallet, password } = data;
|
||||
|
||||
return Signer.getSeed(wallet, password);
|
||||
}
|
||||
|
||||
function compile (data) {
|
||||
const { build } = data;
|
||||
|
||||
return getCompiler(build)
|
||||
.then((compiler) => {
|
||||
return SolidityUtils.compile(data, compiler);
|
||||
});
|
||||
}
|
||||
|
||||
function setFiles (files) {
|
||||
const prevFiles = self.files;
|
||||
const nextFiles = files.reduce((obj, file) => {
|
||||
obj[file.name] = file.sourcecode;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
self.files = {
|
||||
...prevFiles,
|
||||
...nextFiles
|
||||
};
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
function getCompiler (build) {
|
||||
const { longVersion } = build;
|
||||
|
||||
const fetcher = (url) => {
|
||||
const request = new Request(url);
|
||||
|
||||
return cachedFetcher(request);
|
||||
};
|
||||
|
||||
if (!self.solc[longVersion]) {
|
||||
self.solc[longVersion] = SolidityUtils
|
||||
.getCompiler(build, fetcher)
|
||||
.then((compiler) => {
|
||||
self.solc[longVersion] = compiler;
|
||||
return compiler;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(self.solc[longVersion]);
|
||||
}
|
||||
|
@ -50,18 +50,24 @@ export default class SolidityUtils {
|
||||
return compiled;
|
||||
}
|
||||
|
||||
static getCompiler (build, _fetcher) {
|
||||
static getCompiler (build) {
|
||||
const { longVersion, path } = build;
|
||||
|
||||
const URL = `https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/bin/${path}`;
|
||||
|
||||
const fetcher = typeof _fetcher === 'function'
|
||||
? _fetcher
|
||||
: (url) => fetch(url);
|
||||
|
||||
const isWorker = typeof window !== 'object';
|
||||
|
||||
return fetcher(URL)
|
||||
if (isWorker) {
|
||||
return new Promise((resolve, reject) => {
|
||||
self.importScripts(URL);
|
||||
|
||||
setTimeout(() => {
|
||||
const compiler = solc(self.Module);
|
||||
|
||||
return resolve(compiler);
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
return fetch(URL)
|
||||
.then((r) => r.text())
|
||||
.then((code) => {
|
||||
// `window` for main thread, `self` for workers
|
||||
|
@ -105,7 +105,7 @@ class WriteContract extends Component {
|
||||
className={ styles.editor }
|
||||
style={ { flex: `${size}%` } }
|
||||
>
|
||||
<h2>{ this.renderTitle() }</h2>
|
||||
<h2>asd{ this.renderTitle() }</h2>
|
||||
|
||||
<Editor
|
||||
ref='editor'
|
||||
|
92
js/src/webWorker.js
Normal file
92
js/src/webWorker.js
Normal file
@ -0,0 +1,92 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import registerPromiseWorker from 'promise-worker/register';
|
||||
import { Signer } from '~/util/signer';
|
||||
import SolidityUtils from '~/util/solidity';
|
||||
|
||||
registerPromiseWorker((msg) => {
|
||||
return handleMessage(msg);
|
||||
});
|
||||
|
||||
self.solc = {};
|
||||
self.files = {};
|
||||
|
||||
function handleMessage (message) {
|
||||
switch (message.action) {
|
||||
case 'compile':
|
||||
return compile(message.data);
|
||||
|
||||
case 'load':
|
||||
return getCompiler(message.data).then(() => 'ok');
|
||||
|
||||
case 'setFiles':
|
||||
return setFiles(message.data);
|
||||
|
||||
case 'getSignerSeed':
|
||||
return getSignerSeed(message.data);
|
||||
|
||||
default:
|
||||
console.warn(`unknown action "${message.action}"`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getSignerSeed (data) {
|
||||
console.log('deriving seed from service-worker');
|
||||
const { wallet, password } = data;
|
||||
|
||||
return Signer.getSeed(wallet, password);
|
||||
}
|
||||
|
||||
function compile (data) {
|
||||
const { build } = data;
|
||||
|
||||
return getCompiler(build)
|
||||
.then((compiler) => {
|
||||
return SolidityUtils.compile(data, compiler);
|
||||
});
|
||||
}
|
||||
|
||||
function setFiles (files) {
|
||||
const prevFiles = self.files;
|
||||
const nextFiles = files.reduce((obj, file) => {
|
||||
obj[file.name] = file.sourcecode;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
self.files = {
|
||||
...prevFiles,
|
||||
...nextFiles
|
||||
};
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
function getCompiler (build) {
|
||||
const { longVersion } = build;
|
||||
|
||||
if (!self.solc[longVersion]) {
|
||||
self.solc[longVersion] = SolidityUtils
|
||||
.getCompiler(build)
|
||||
.then((compiler) => {
|
||||
self.solc[longVersion] = compiler;
|
||||
return compiler;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(self.solc[longVersion]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user