Unverified Commit 9e506e99 authored by yann300's avatar yann300 Committed by GitHub

Merge pull request #2828 from ethereum/wasmBuilds

Load wasm builds if available
parents f59019cb 9630deca
...@@ -165,6 +165,7 @@ ...@@ -165,6 +165,7 @@
"nightwatch_local_firefox": "nightwatch --config nightwatch.js --env firefox", "nightwatch_local_firefox": "nightwatch --config nightwatch.js --env firefox",
"nightwatch_local_chrome": "nightwatch --config nightwatch.js --env chrome", "nightwatch_local_chrome": "nightwatch --config nightwatch.js --env chrome",
"nightwatch_local_ballot": "nightwatch ./test-browser/tests/ballot.test.js --config nightwatch.js --env chrome ", "nightwatch_local_ballot": "nightwatch ./test-browser/tests/ballot.test.js --config nightwatch.js --env chrome ",
"nightwatch_local_usingWorker": "nightwatch ./test-browser/tests/usingWebWorker.test.js --config nightwatch.js --env chrome ",
"nightwatch_local_libraryDeployment": "nightwatch ./test-browser/tests/libraryDeployment.test.js --config nightwatch.js --env chrome ", "nightwatch_local_libraryDeployment": "nightwatch ./test-browser/tests/libraryDeployment.test.js --config nightwatch.js --env chrome ",
"nightwatch_local_solidityImport": "nightwatch ./test-browser/tests/solidityImport.test.js --config nightwatch.js --env chrome ", "nightwatch_local_solidityImport": "nightwatch ./test-browser/tests/solidityImport.test.js --config nightwatch.js --env chrome ",
"nightwatch_local_recorder": "nightwatch ./test-browser/tests/recorder.test.js --config nightwatch.js --env chrome ", "nightwatch_local_recorder": "nightwatch ./test-browser/tests/recorder.test.js --config nightwatch.js --env chrome ",
......
'use strict' 'use strict'
import { canUseWorker } from './compiler-utils' import { canUseWorker, urlFromVersion } from './compiler-utils'
import { Compiler } from 'remix-solidity' import { Compiler } from 'remix-solidity'
import CompilerAbstract from './compiler-abstract' import CompilerAbstract from './compiler-abstract'
...@@ -9,7 +9,7 @@ export const compile = async (compilationTargets, settings) => { ...@@ -9,7 +9,7 @@ export const compile = async (compilationTargets, settings) => {
const compiler = new Compiler(() => {}) const compiler = new Compiler(() => {})
compiler.set('evmVersion', settings.evmVersion) compiler.set('evmVersion', settings.evmVersion)
compiler.set('optimize', settings.optimize) compiler.set('optimize', settings.optimize)
compiler.loadVersion(canUseWorker(settings.version), settings.compilerUrl) compiler.loadVersion(canUseWorker(settings.version), urlFromVersion(settings.version))
compiler.event.register('compilationFinished', (success, compilationData, source) => { compiler.event.register('compilationFinished', (success, compilationData, source) => {
if (!success) return reject(compilationData) if (!success) return reject(compilationData)
resolve(new CompilerAbstract(settings.version, compilationData, source)) resolve(new CompilerAbstract(settings.version, compilationData, source))
......
const ethutil = require('ethereumjs-util') const ethutil = require('ethereumjs-util')
import * as packageJson from '../../../package.json' import * as packageJson from '../../../package.json'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { urlFromVersion } from './compiler-utils'
import { compile } from './compiler-helpers' import { compile } from './compiler-helpers'
import globalRegistry from '../../global/registry' import globalRegistry from '../../global/registry'
...@@ -108,8 +107,7 @@ export default class FetchAndCompile extends Plugin { ...@@ -108,8 +107,7 @@ export default class FetchAndCompile extends Plugin {
version: data.metadata.compiler.version, version: data.metadata.compiler.version,
languageName: data.metadata.language, languageName: data.metadata.language,
evmVersion: data.metadata.settings.evmVersion, evmVersion: data.metadata.settings.evmVersion,
optimize: data.metadata.settings.optimizer.enabled, optimize: data.metadata.settings.optimizer.enabled
compilerUrl: urlFromVersion(data.metadata.compiler.version)
} }
try { try {
setTimeout(_ => this.emit('compiling', settings), 0) setTimeout(_ => this.emit('compiling', settings), 0)
......
const semver = require('semver') const semver = require('semver')
const minixhr = require('minixhr')
/* global Worker */ /* global Worker */
export const baseUrl = 'https://solc-bin.ethereum.org/bin' export const baseURLBin = 'https://solc-bin.ethereum.org/bin'
export const baseURLWasm = 'https://solc-bin.ethereum.org/wasm'
export const pathToURL = {}
/**
* Retrieves the URL of the given compiler version
* @param version is the version of compiler with or without 'soljson-v' prefix and .js postfix
*/
export function urlFromVersion (version) { export function urlFromVersion (version) {
return `${baseUrl}/soljson-v${version}.js` if (!version.startsWith('soljson-v')) version = 'soljson-v' + version
if (!version.endsWith('.js')) version = version + '.js'
return `${pathToURL[version]}/${version}`
} }
/** /**
* Checks if the worker can be used to load a compiler. * Checks if the worker can be used to load a compiler.
* checks a compiler whitelist, browser support and OS. * checks a compiler whitelist, browser support and OS.
*/ */
export function canUseWorker (selectedVersion) { export function canUseWorker (selectedVersion) {
// Following restrictions should be deleted when Solidity will release fixed versions of compilers.
// See https://github.com/ethereum/remix-ide/issues/2461
const isChrome = !!window.chrome
const os = retrieveOS()
// define a whitelist for Linux
const linuxWL = ['0.4.26', '0.5.3', '0.5.4', '0.5.5']
const version = semver.coerce(selectedVersion) const version = semver.coerce(selectedVersion)
// defining whitelist for chrome const isNightly = selectedVersion.includes('nightly')
let isFromWhiteList = false return browserSupportWorker() && (
switch (os) { semver.gt(version, '0.6.3') ||
case 'Windows': semver.gt(version, '0.3.6') && !isNightly
isFromWhiteList = semver.gt(version, '0.5.2') || version === '0.4.26' )
break
case 'Linux':
isFromWhiteList = semver.gt(version, '0.5.13') || linuxWL.includes(version)
break
default :
isFromWhiteList = true
}
return browserSupportWorker() && (!isChrome || (isChrome && isFromWhiteList))
} }
function browserSupportWorker () { function browserSupportWorker () {
return document.location.protocol !== 'file:' && Worker !== undefined return document.location.protocol !== 'file:' && Worker !== undefined
} }
function retrieveOS () { // returns a promise for minixhr
let osName = 'Unknown OS' export function promisedMiniXhr (url) {
if (navigator.platform.indexOf('Win') !== -1) { return new Promise((resolve, reject) => {
osName = 'Windows' minixhr(url, (json, event) => {
} else if (navigator.platform.indexOf('Linux') !== -1) { resolve({ json, event })
osName = 'Linux' })
} })
return osName
} }
'use strict' 'use strict'
const basic = `pragma solidity >=0.2.0 <0.7.0;
/**
* @title Basic contract
*/
contract Basic {
uint someVar;
constructor() public {}
}`
const storage = `pragma solidity >=0.4.22 <0.7.0; const storage = `pragma solidity >=0.4.22 <0.7.0;
/** /**
...@@ -245,5 +255,6 @@ module.exports = { ...@@ -245,5 +255,6 @@ module.exports = {
storage: { name: '1_Storage.sol', content: storage }, storage: { name: '1_Storage.sol', content: storage },
owner: { name: '2_Owner.sol', content: owner }, owner: { name: '2_Owner.sol', content: owner },
ballot: { name: '3_Ballot.sol', content: ballot }, ballot: { name: '3_Ballot.sol', content: ballot },
ballot_test: { name: '4_Ballot_test.sol', content: ballotTest } ballot_test: { name: '4_Ballot_test.sol', content: ballotTest },
basic: { name: 'basic.sol', content: basic }
} }
...@@ -93,7 +93,10 @@ class FileProvider { ...@@ -93,7 +93,10 @@ class FileProvider {
cb = cb || function () {} cb = cb || function () {}
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
var exists = window.remixFileSystem.existsSync(unprefixedpath) var exists = window.remixFileSystem.existsSync(unprefixedpath)
if (exists && window.remixFileSystem.readFileSync(unprefixedpath, 'utf8') === content) return true if (exists && window.remixFileSystem.readFileSync(unprefixedpath, 'utf8') === content) {
cb()
return true
}
if (!exists && unprefixedpath.indexOf('/') !== -1) { if (!exists && unprefixedpath.indexOf('/') !== -1) {
this.createDir(path) this.createDir(path)
} }
......
...@@ -116,6 +116,7 @@ class CompileTab extends ViewPlugin { ...@@ -116,6 +116,7 @@ class CompileTab extends ViewPlugin {
this.fileManager.events.on('noFileSelected', this.data.eventHandlers.onNoFileSelected) this.fileManager.events.on('noFileSelected', this.data.eventHandlers.onNoFileSelected)
this.data.eventHandlers.onCompilationFinished = (success, data, source) => { this.data.eventHandlers.onCompilationFinished = (success, data, source) => {
this._view.errorContainer.appendChild(yo`<span data-id="compilationFinishedWith_${this.getCurrentVersion()}"></span>`)
if (success) { if (success) {
// forwarding the event to the appManager infra // forwarding the event to the appManager infra
this.emit('compilationFinished', source.target, source, 'soljson', data) this.emit('compilationFinished', source.target, source, 'soljson', data)
...@@ -411,7 +412,7 @@ class CompileTab extends ViewPlugin { ...@@ -411,7 +412,7 @@ class CompileTab extends ViewPlugin {
render () { render () {
if (this._view.el) return this._view.el if (this._view.el) return this._view.el
this.onActivationInternal() this.onActivationInternal()
this._view.errorContainer = yo`<div class="${css.errorBlobs} p-4"></div>` this._view.errorContainer = yo`<div class="${css.errorBlobs} p-4" data-id="compiledErrors" ></div>`
this._view.contractSelection = this.contractSelection() this._view.contractSelection = this.contractSelection()
this._view.compilerContainer = this.compilerContainer.render() this._view.compilerContainer = this.compilerContainer.render()
this.compilerContainer.activate() this.compilerContainer.activate()
......
const yo = require('yo-yo') const yo = require('yo-yo')
const minixhr = require('minixhr')
const helper = require('../../../lib/helper') const helper = require('../../../lib/helper')
const addTooltip = require('../../ui/tooltip') const addTooltip = require('../../ui/tooltip')
const semver = require('semver') const semver = require('semver')
const modalDialogCustom = require('../../ui/modal-dialog-custom') const modalDialogCustom = require('../../ui/modal-dialog-custom')
const css = require('../styles/compile-tab-styles') const css = require('../styles/compile-tab-styles')
import { canUseWorker } from '../../compiler/compiler-utils' import { canUseWorker, baseURLBin, baseURLWasm, urlFromVersion, pathToURL, promisedMiniXhr } from '../../compiler/compiler-utils'
class CompilerContainer { class CompilerContainer {
...@@ -24,8 +23,7 @@ class CompilerContainer { ...@@ -24,8 +23,7 @@ class CompilerContainer {
timeout: 300, timeout: 300,
allversions: null, allversions: null,
selectedVersion: null, selectedVersion: null,
defaultVersion: 'soljson-v0.6.6+commit.6c089d02.js', // this default version is defined: in makeMockCompiler (for browser test) and in package.json (downloadsolc_root) for the builtin compiler defaultVersion: 'soljson-v0.6.6+commit.6c089d02.js' // this default version is defined: in makeMockCompiler (for browser test) and in package.json (downloadsolc_root) for the builtin compiler
baseurl: 'https://solc-bin.ethereum.org/bin'
} }
} }
...@@ -383,13 +381,13 @@ class CompilerContainer { ...@@ -383,13 +381,13 @@ class CompilerContainer {
if (this.data.selectedVersion.indexOf('soljson') !== 0 || helper.checkSpecialChars(this.data.selectedVersion)) { if (this.data.selectedVersion.indexOf('soljson') !== 0 || helper.checkSpecialChars(this.data.selectedVersion)) {
return console.log('loading ' + this.data.selectedVersion + ' not allowed') return console.log('loading ' + this.data.selectedVersion + ' not allowed')
} }
url = `${this.data.baseurl}/${this.data.selectedVersion}` url = `${urlFromVersion(this.data.selectedVersion)}`
} }
// Workers cannot load js on "file:"-URLs and we get a // Workers cannot load js on "file:"-URLs and we get a
// "Uncaught RangeError: Maximum call stack size exceeded" error on Chromium, // "Uncaught RangeError: Maximum call stack size exceeded" error on Chromium,
// resort to non-worker version in that case. // resort to non-worker version in that case.
if (canUseWorker(this.data.selectedVersion)) { if (this.data.selectedVersion !== 'builtin' && canUseWorker(this.data.selectedVersion)) {
this.compileTabLogic.compiler.loadVersion(true, url) this.compileTabLogic.compiler.loadVersion(true, url)
this.setVersionText('(loading using worker)') this.setVersionText('(loading using worker)')
} else { } else {
...@@ -413,27 +411,42 @@ class CompilerContainer { ...@@ -413,27 +411,42 @@ class CompilerContainer {
if (this._view.version) this._view.version.innerText = text if (this._view.version) this._view.version.innerText = text
} }
fetchAllVersion (callback) { // fetching both normal and wasm builds and creating a [version, baseUrl] map
minixhr(`${this.data.baseurl}/list.json`, (json, event) => { async fetchAllVersion (callback) {
// @TODO: optimise and cache results to improve app loading times #2461 let allVersions, selectedVersion, allVersionsWasm
var allversions, selectedVersion // fetch normal builds
if (event.type !== 'error') { const binRes = await promisedMiniXhr(`${baseURLBin}/list.json`)
try { // fetch wasm builds
const data = JSON.parse(json) const wasmRes = await promisedMiniXhr(`${baseURLWasm}/list.json`)
allversions = data.builds.slice().reverse() if (binRes.event.type === 'error' && wasmRes.event.type === 'error') {
selectedVersion = this.data.defaultVersion allVersions = [{ path: 'builtin', longVersion: 'latest local version' }]
if (this.queryParams.get().version) selectedVersion = this.queryParams.get().version selectedVersion = 'builtin'
} catch (e) { callback(allVersions, selectedVersion)
addTooltip('Cannot load compiler version list. It might have been blocked by an advertisement blocker. Please try deactivating any of them from this page and reload.') }
} try {
} else { allVersions = JSON.parse(binRes.json).builds.slice().reverse()
allversions = [{ path: 'builtin', longVersion: 'latest local version' }] selectedVersion = this.data.defaultVersion
selectedVersion = 'builtin' if (this.queryParams.get().version) selectedVersion = this.queryParams.get().version
if (wasmRes.event.type !== 'error') {
allVersionsWasm = JSON.parse(wasmRes.json).builds.slice().reverse()
} }
callback(allversions, selectedVersion) } catch (e) {
}) addTooltip('Cannot load compiler version list. It might have been blocked by an advertisement blocker. Please try deactivating any of them from this page and reload. Error: ' + e)
}
// replace in allVersions those compiler builds which exist in allVersionsWasm with new once
if (allVersionsWasm && allVersions) {
allVersions.forEach((compiler, index) => {
const wasmIndex = allVersionsWasm.findIndex(wasmCompiler => { return wasmCompiler.longVersion === compiler.longVersion })
if (wasmIndex !== -1) {
allVersions[index] = allVersionsWasm[wasmIndex]
pathToURL[compiler.path] = baseURLWasm
} else {
pathToURL[compiler.path] = baseURLBin
}
})
}
callback(allVersions, selectedVersion)
} }
scheduleCompilation () { scheduleCompilation () {
if (!this.config.get('autoCompile')) return if (!this.config.get('autoCompile')) return
if (this.data.compileTimeout) window.clearTimeout(this.data.compileTimeout) if (this.data.compileTimeout) window.clearTimeout(this.data.compileTimeout)
......
...@@ -4,7 +4,7 @@ var tooltip = require('../ui/tooltip') ...@@ -4,7 +4,7 @@ var tooltip = require('../ui/tooltip')
var css = require('./styles/test-tab-styles') var css = require('./styles/test-tab-styles')
var remixTests = require('remix-tests') var remixTests = require('remix-tests')
import { ViewPlugin } from '@remixproject/engine' import { ViewPlugin } from '@remixproject/engine'
import { canUseWorker, baseUrl } from '../compiler/compiler-utils' import { canUseWorker, urlFromVersion } from '../compiler/compiler-utils'
const TestTabLogic = require('./testTab/testTab') const TestTabLogic = require('./testTab/testTab')
...@@ -301,7 +301,7 @@ module.exports = class TestTab extends ViewPlugin { ...@@ -301,7 +301,7 @@ module.exports = class TestTab extends ViewPlugin {
let runningTest = {} let runningTest = {}
runningTest[path] = { content } runningTest[path] = { content }
const {currentVersion, evmVersion, optimize} = this.compileTab.getCurrentCompilerConfig() const {currentVersion, evmVersion, optimize} = this.compileTab.getCurrentCompilerConfig()
const currentCompilerUrl = baseUrl + '/' + currentVersion const currentCompilerUrl = urlFromVersion(currentVersion)
const compilerConfig = { const compilerConfig = {
currentCompilerUrl, currentCompilerUrl,
evmVersion, evmVersion,
...@@ -327,7 +327,7 @@ module.exports = class TestTab extends ViewPlugin { ...@@ -327,7 +327,7 @@ module.exports = class TestTab extends ViewPlugin {
const runningTest = {} const runningTest = {}
runningTest[testFilePath] = { content } runningTest[testFilePath] = { content }
const {currentVersion, evmVersion, optimize} = this.compileTab.getCurrentCompilerConfig() const {currentVersion, evmVersion, optimize} = this.compileTab.getCurrentCompilerConfig()
const currentCompilerUrl = baseUrl + '/' + currentVersion const currentCompilerUrl = urlFromVersion(currentVersion)
const compilerConfig = { const compilerConfig = {
currentCompilerUrl, currentCompilerUrl,
evmVersion, evmVersion,
......
...@@ -84,4 +84,3 @@ function find (args, query) { ...@@ -84,4 +84,3 @@ function find (args, query) {
}) })
return isMatch return isMatch
} }
const EventEmitter = require('events')
class NoWorkerErrorFor extends EventEmitter {
command (version) {
this.api.perform((done) => {
noWorkerErrorFor(this.api, version, () => {
done()
this.emit('complete')
})
})
return this
}
}
function noWorkerErrorFor (browser, version, callback) {
browser
.setSolidityCompilerVersion(version)
.click('*[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('*[data-id="compilationFinishedWith_' + version + '"]', 10000)
.notContainsText('*[data-id="compiledErrors"]', 'worker error:undefined')
.notContainsText('*[data-id="compiledErrors"]', 'Uncaught RangeError: Maximum call stack size exceeded')
.notContainsText('*[data-id="compiledErrors"]', 'RangeError: Maximum call stack size exceeded')
.perform(() => {
callback()
})
}
module.exports = NoWorkerErrorFor
...@@ -31,8 +31,7 @@ module.exports = { ...@@ -31,8 +31,7 @@ module.exports = {
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgHash"]') .assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgSignature"]') .assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.modalFooterOKClick() .modalFooterOKClick()
.pause(2000) .waitForElementPresent('*[data-id="modalDialogContainer"]', 12000)
.waitForElementPresent('*[data-id="modalDialogContainer"]')
.assert.elementPresent('*[data-id="settingsRemixRunSignMsgHash"]') .assert.elementPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.elementPresent('*[data-id="settingsRemixRunSignMsgSignature"]') .assert.elementPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.modalFooterOKClick() .modalFooterOKClick()
...@@ -145,8 +144,8 @@ module.exports = { ...@@ -145,8 +144,8 @@ module.exports = {
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]') .waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]') .click('*[data-id="Deploy - transact (not payable)"]')
.pause(2000) .waitForElementPresent('*[data-id="modalDialogContainer"]', 15000)
.waitForElementPresent('*[data-id="modalDialogContainer"]') .pause(10000)
.assert.containsText('*[data-id="modalDialogModalBody"]', 'You are creating a transaction on the main network. Click confirm if you are sure to continue.') .assert.containsText('*[data-id="modalDialogModalBody"]', 'You are creating a transaction on the main network. Click confirm if you are sure to continue.')
.modalFooterCancelClick() .modalFooterCancelClick()
}, },
......
...@@ -86,7 +86,7 @@ module.exports = { ...@@ -86,7 +86,7 @@ module.exports = {
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]') .scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.pause(5000) .pause(5000)
.click('*[data-id="testTabRunTestsTabStopAction"]') .click('*[data-id="testTabRunTestsTabStopAction"]')
.pause(2000) .pause(1000)
.assert.containsText('*[data-id="testTabRunTestsTabStopAction"]', 'Stopping') .assert.containsText('*[data-id="testTabRunTestsTabStopAction"]', 'Stopping')
.waitForElementPresent('*[data-id="testTabSolidityUnitTestsOutputheader"]', 40000) .waitForElementPresent('*[data-id="testTabSolidityUnitTestsOutputheader"]', 40000)
.assert.containsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'browser/ks2b_test.sol') .assert.containsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'browser/ks2b_test.sol')
......
'use strict'
var examples = require('../../src/app/editor/example-contracts')
var init = require('../helpers/init')
var sauce = require('./sauce')
var sources = [
{'browser/basic.sol': {content: examples.basic.content}}
]
module.exports = {
before: function (browser, done) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Using Web Worker': function (browser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('fileExplorers')
.openFile('browser/basic.sol')
.clickLaunchIcon('solidity')
.execute(() => {
document.getElementById('nightlies').checked = true
})
.noWorkerErrorFor('soljson-v0.3.4+commit.7dab890.js')
.noWorkerErrorFor('soljson-v0.6.5+commit.f956cc89.js')
.noWorkerErrorFor('soljson-v0.6.8-nightly.2020.5.14+commit.a6d0067b.js')
.noWorkerErrorFor('soljson-v0.6.0-nightly.2019.12.17+commit.d13438ee.js')
.noWorkerErrorFor('soljson-v0.4.26+commit.4563c3fc.js')
.execute(() => {
document.getElementById('nightlies').checked = false
})
},
tearDown: sauce
}
Markdown is supported
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