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",
|
"scryptsy": "2.0.0",
|
||||||
"solc": "ngotchac/solc-js",
|
"solc": "ngotchac/solc-js",
|
||||||
"store": "1.3.20",
|
"store": "1.3.20",
|
||||||
|
"sw-toolbox": "^3.6.0",
|
||||||
"u2f-api": "0.0.9",
|
"u2f-api": "0.0.9",
|
||||||
"u2f-api-polyfill": "0.4.3",
|
"u2f-api-polyfill": "0.4.3",
|
||||||
"uglify-js": "2.8.2",
|
"uglify-js": "2.8.2",
|
||||||
@ -210,6 +211,7 @@
|
|||||||
"validator": "6.2.0",
|
"validator": "6.2.0",
|
||||||
"web3": "0.17.0-beta",
|
"web3": "0.17.0-beta",
|
||||||
"whatwg-fetch": "2.0.1",
|
"whatwg-fetch": "2.0.1",
|
||||||
|
"worker-loader": "^0.8.0",
|
||||||
"zxcvbn": "4.4.1"
|
"zxcvbn": "4.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ contract multisig {
|
|||||||
|
|
||||||
// TODO: document
|
// TODO: document
|
||||||
function execute(address _to, uint _value, bytes _data) external returns (bytes32 o_hash);
|
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:
|
// usage:
|
||||||
|
@ -16,15 +16,22 @@
|
|||||||
|
|
||||||
import PromiseWorker from 'promise-worker';
|
import PromiseWorker from 'promise-worker';
|
||||||
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
||||||
|
import WebWorker from 'worker-loader!~/webWorker.js';
|
||||||
|
|
||||||
import { setWorker } from './workerActions';
|
import { setWorker } from './workerActions';
|
||||||
|
|
||||||
function getWorker () {
|
// Setup the Service Worker
|
||||||
// Setup the Service Worker
|
setupServiceWorker()
|
||||||
if ('serviceWorker' in navigator) {
|
.then(() => console.log('SW is setup'))
|
||||||
return runtime
|
.catch((error) => console.error('SW error', error));
|
||||||
.register()
|
|
||||||
.then(() => navigator.serviceWorker.ready)
|
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) => {
|
.then((registration) => {
|
||||||
const worker = registration.active;
|
const worker = registration.active;
|
||||||
|
|
||||||
@ -32,9 +39,34 @@ function getWorker () {
|
|||||||
|
|
||||||
return new PromiseWorker(worker);
|
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) => {
|
export const setupWorker = (store) => {
|
||||||
@ -43,27 +75,16 @@ export const setupWorker = (store) => {
|
|||||||
const state = getState();
|
const state = getState();
|
||||||
const stateWorker = state.worker.worker;
|
const stateWorker = state.worker.worker;
|
||||||
|
|
||||||
if (stateWorker !== undefined && !(stateWorker && stateWorker._worker.state === 'redundant')) {
|
if (stateWorker !== undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getWorker()
|
getWorker()
|
||||||
.then((worker) => {
|
.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));
|
dispatch(setWorker(worker));
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('sw', error);
|
console.error('setupWorker', error);
|
||||||
dispatch(setWorker(null));
|
dispatch(setWorker(null));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import registerPromiseWorker from 'promise-worker/register';
|
import toolbox from 'sw-toolbox';
|
||||||
import { Signer } from '~/util/signer';
|
|
||||||
import SolidityUtils from '~/util/solidity';
|
|
||||||
|
|
||||||
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) => {
|
self.addEventListener('install', (event) => {
|
||||||
event.waitUntil(self.skipWaiting());
|
event.waitUntil(self.skipWaiting());
|
||||||
@ -31,126 +31,3 @@ self.addEventListener('install', (event) => {
|
|||||||
self.addEventListener('activate', (event) => {
|
self.addEventListener('activate', (event) => {
|
||||||
event.waitUntil(self.clients.claim());
|
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;
|
return compiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getCompiler (build, _fetcher) {
|
static getCompiler (build) {
|
||||||
const { longVersion, path } = build;
|
const { longVersion, path } = build;
|
||||||
|
|
||||||
const URL = `https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/bin/${path}`;
|
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';
|
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((r) => r.text())
|
||||||
.then((code) => {
|
.then((code) => {
|
||||||
// `window` for main thread, `self` for workers
|
// `window` for main thread, `self` for workers
|
||||||
|
@ -105,7 +105,7 @@ class WriteContract extends Component {
|
|||||||
className={ styles.editor }
|
className={ styles.editor }
|
||||||
style={ { flex: `${size}%` } }
|
style={ { flex: `${size}%` } }
|
||||||
>
|
>
|
||||||
<h2>{ this.renderTitle() }</h2>
|
<h2>asd{ this.renderTitle() }</h2>
|
||||||
|
|
||||||
<Editor
|
<Editor
|
||||||
ref='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