Merge pull request #2590 from ethereum/refactor_logic9

refactor vm provider to use remix-simulator
pull/5370/head
yann300 5 years ago committed by GitHub
commit 64a4b95fc2
  1. 1075
      package-lock.json
  2. 12
      package.json
  3. 2
      src/app/tabs/runTab/settings.js
  4. 18
      src/blockchain/blockchain.js
  5. 8
      src/blockchain/providers/injected.js
  6. 8
      src/blockchain/providers/node.js
  7. 73
      src/blockchain/providers/vm.js
  8. 16
      test-browser/commands/selectAccount.js
  9. 1
      test-browser/tests/ballot.js
  10. 2
      test-browser/tests/libraryDeployment.js
  11. 1
      test-browser/tests/publishContract.js
  12. 15
      test-browser/tests/recorder.js
  13. 5
      test-browser/tests/signingMessage.js
  14. 1
      test-browser/tests/specialFunctions.js
  15. 1
      test-browser/tests/transactionExecution.js

1075
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -56,11 +56,12 @@
"npm-run-all": "^4.0.2",
"onchange": "^3.2.1",
"remix-analyzer": "0.3.23",
"remix-debug": "0.3.26",
"remix-lib": "0.4.22",
"remix-solidity": "0.3.25",
"remix-debug": "0.3.27",
"remix-lib": "0.4.23",
"remix-solidity": "0.3.26",
"remix-tabs": "1.0.48",
"remix-tests": "0.1.28",
"remix-tests": "0.1.29",
"remix-simulator": "0.1.9-beta.1",
"remixd": "0.1.8-alpha.10",
"request": "^2.83.0",
"rimraf": "^2.6.1",
@ -145,13 +146,14 @@
"remix-ide": "./bin/remix-ide"
},
"scripts": {
"setupremix": "npm run linkremixdebug && npm run linkremixlib && npm run linkremixsolidity && npm run linkremixanalyzer && npm run linkremixtests",
"setupremix": "npm run linkremixdebug && npm run linkremixlib && npm run linkremixsolidity && npm run linkremixanalyzer && npm run linkremixtests && npm run linkremixsimulator",
"pullremix": "git clone https://github.com/ethereum/remix",
"linkremixlib": "cd node_modules && rm -rf remix-lib && ln -s ../../remix/remix-lib remix-lib && cd ..",
"linkremixsolidity": "cd node_modules && rm -rf remix-solidity && ln -s ../../remix/remix-solidity remix-solidity && cd ..",
"linkremixtests": "cd node_modules && rm -rf remix-tests && ln -s ../../remix/remix-tests remix-tests && cd ..",
"linkremixdebug": "cd node_modules && rm -rf remix-debug && ln -s ../../remix/remix-debug remix-debug && cd ..",
"linkremixanalyzer": "cd node_modules && rm -rf remix-analyzer && ln -s ../../remix/remix-analyzer remix-analyzer && cd ..",
"linkremixsimulator": "cd node_modules && rm -rf remix-simulator && ln -s ../../remix/remix-simulator remix-simulator && cd ..",
"build": "browserify src/index.js -o build/app.js --exclude solc",
"build_debugger": "browserify src/app/debugger/remix-debugger/index.js -o src/app/debugger/remix-debugger/build/app.js",
"browsertest": "sleep 5 && npm run nightwatch_local",

@ -97,7 +97,7 @@ class SettingsUI {
</span>
</label>
<div class="${css.account}">
<select name="txorigin" class="form-control ${css.select} custom-select" id="txorigin"></select>
<select data-id="runTabSelectAccount" name="txorigin" class="form-control ${css.select} custom-select" id="txorigin"></select>
${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)}
<i id="remixRunSignMsg" class="fas fa-edit ${css.icon}" aria-hidden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i>
</div>

@ -56,18 +56,6 @@ class Blockchain {
this.executionContext.event.register('removeProvider', (name) => {
this.event.trigger('removeProvider', [name])
})
// this.udapp.event.register('initiatingTransaction', (timestamp, tx, payLoad) => {
// this.event.trigger('initiatingTransaction', [timestamp, tx, payLoad])
// })
// this.udapp.event.register('transactionExecuted', (error, from, to, data, call, txResult, timestamp) => {
// this.event.trigger('transactionExecuted', [error, from, to, data, call, txResult, timestamp])
// })
// this.udapp.event.register('transactionBroadcasted', (txhash, networkName) => {
// this.event.trigger('transactionBroadcasted', [txhash, networkName])
// })
}
setupProviders () {
@ -321,7 +309,8 @@ class Blockchain {
resetEnvironment () {
this.getCurrentProvider().resetEnvironment()
// TODO: most params here can be refactored away in txRunner
this.txRunner = new TxRunner(this.providers.vm.accounts, {
// this.txRunner = new TxRunner(this.providers.vm.accounts, {
this.txRunner = new TxRunner(this.providers.vm.RemixSimulatorProvider.Accounts.accounts, {
// TODO: only used to check value of doNotShowTransactionConfirmationAgain property
config: this.config,
// TODO: to refactor, TxRunner already has access to executionContext
@ -430,7 +419,8 @@ class Blockchain {
if (err) return next(err)
if (!address) return next('No accounts available')
if (self.executionContext.isVM() && !self.providers.vm.accounts[address]) {
// if (self.executionContext.isVM() && !self.providers.vm.accounts[address]) {
if (self.executionContext.isVM() && !self.providers.vm.RemixSimulatorProvider.Accounts.accounts[address]) {
return next('Invalid account selected')
}
next(null, address, value, gasLimit)

@ -1,5 +1,5 @@
const Web3 = require('web3')
const { stripHexPrefix } = require('ethereumjs-util')
const { stripHexPrefix, hashPersonalMessage } = require('ethereumjs-util')
class InjectedProvider {
@ -35,10 +35,10 @@ class InjectedProvider {
}
signMessage (message, account, _passphrase, cb) {
const hashedMsg = Web3.utils.sha3(message)
const messageHash = hashPersonalMessage(Buffer.from(message))
try {
this.executionContext.web3().eth.sign(hashedMsg, account, (error, signedData) => {
cb(error, hashedMsg, signedData)
this.executionContext.web3().eth.sign(message, account, (error, signedData) => {
cb(error, '0x' + messageHash.toString('hex'), signedData)
})
} catch (e) {
cb(e.message)

@ -1,5 +1,5 @@
const Web3 = require('web3')
const { stripHexPrefix } = require('ethereumjs-util')
const { stripHexPrefix, hashPersonalMessage } = require('ethereumjs-util')
const Personal = require('web3-eth-personal')
class NodeProvider {
@ -43,11 +43,11 @@ class NodeProvider {
}
signMessage (message, account, passphrase, cb) {
const hashedMsg = Web3.utils.sha3(message)
const messageHash = hashPersonalMessage(Buffer.from(message))
try {
const personal = new Personal(this.executionContext.web3().currentProvider)
personal.sign(hashedMsg, account, passphrase, (error, signedData) => {
cb(error, hashedMsg, signedData)
personal.sign(message, account, passphrase, (error, signedData) => {
cb(error, '0x' + messageHash.toString('hex'), signedData)
})
} catch (e) {
cb(e.message)

@ -1,91 +1,66 @@
const Web3 = require('web3')
const { BN, privateToAddress, toChecksumAddress, isValidPrivate, stripHexPrefix } = require('ethereumjs-util')
const crypto = require('crypto')
const ethJSUtil = require('ethereumjs-util')
const { BN, privateToAddress, stripHexPrefix, hashPersonalMessage } = require('ethereumjs-util')
const RemixSimulator = require('remix-simulator')
class VMProvider {
constructor (executionContext) {
this.executionContext = executionContext
this.RemixSimulatorProvider = new RemixSimulator.Provider({executionContext: this.executionContext})
this.RemixSimulatorProvider.init()
this.web3 = new Web3(this.RemixSimulatorProvider)
this.accounts = {}
}
getAccounts (cb) {
if (!this.accounts) {
cb('No accounts?')
this.web3.eth.getAccounts((err, accounts) => {
if (err) {
return cb('No accounts?')
}
return cb(null, Object.keys(this.accounts))
return cb(null, accounts)
})
}
resetEnvironment () {
this.RemixSimulatorProvider.Accounts.resetAccounts()
this.accounts = {}
this._addAccount('3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511', '0x56BC75E2D63100000')
this._addAccount('2ac6c190b09897cd8987869cc7b918cfea07ee82038d492abce033c75c1b1d0c', '0x56BC75E2D63100000')
this._addAccount('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', '0x56BC75E2D63100000')
this._addAccount('d74aa6d18aa79a05f3473dd030a97d3305737cbc8337d940344345c1f6b72eea', '0x56BC75E2D63100000')
this._addAccount('71975fbf7fe448e004ac7ae54cad0a383c3906055a65468714156a07385e96ce', '0x56BC75E2D63100000')
}
/** Add an account to the list of account (only for Javascript VM) */
_addAccount (privateKey, balance) {
privateKey = Buffer.from(privateKey, 'hex')
const address = privateToAddress(privateKey)
// FIXME: we don't care about the callback, but we should still make this proper
let stateManager = this.executionContext.vm().stateManager
stateManager.getAccount(address, (error, account) => {
if (error) return console.log(error)
account.balance = balance || '0xf00000000000000001'
stateManager.putAccount(address, account, (error) => {
if (error) console.log(error)
})
})
this.accounts[toChecksumAddress('0x' + address.toString('hex'))] = { privateKey, nonce: 0 }
}
// TODO: is still here because of the plugin API
// can be removed later when we update the API
createVMAccount (newAccount) {
const { privateKey, balance } = newAccount
this._addAccount(privateKey, balance)
this.RemixSimulatorProvider.Accounts._addAccount(privateKey, balance)
const privKey = Buffer.from(privateKey, 'hex')
return '0x' + privateToAddress(privKey).toString('hex')
}
newAccount (_passwordPromptCb, cb) {
let privateKey
do {
privateKey = crypto.randomBytes(32)
} while (!isValidPrivate(privateKey))
this._addAccount(privateKey, '0x56BC75E2D63100000')
return cb(null, '0x' + privateToAddress(privateKey).toString('hex'))
this.RemixSimulatorProvider.Accounts.newAccount(cb)
}
getBalanceInEther (address, cb) {
address = stripHexPrefix(address)
this.executionContext.vm().stateManager.getAccount(Buffer.from(address, 'hex'), (err, res) => {
this.web3.eth.getBalance(address, (err, res) => {
if (err) {
return cb('Account not found')
return cb(err)
}
cb(null, Web3.utils.fromWei(new BN(res.balance).toString(10), 'ether'))
cb(null, Web3.utils.fromWei(new BN(res).toString(10), 'ether'))
})
}
getGasPrice (cb) {
this.executionContext.web3().eth.getGasPrice(cb)
this.web3.eth.getGasPrice(cb)
}
signMessage (message, account, _passphrase, cb) {
const personalMsg = ethJSUtil.hashPersonalMessage(Buffer.from(message))
const privKey = this.accounts[account].privateKey
try {
const rsv = ethJSUtil.ecsign(personalMsg, privKey)
const signedData = ethJSUtil.toRpcSig(rsv.v, rsv.r, rsv.s)
cb(null, '0x' + personalMsg.toString('hex'), signedData)
} catch (e) {
cb(e.message)
const messageHash = hashPersonalMessage(Buffer.from(message))
this.web3.eth.sign(message, account, (error, signedData) => {
if (error) {
return cb(error)
}
cb(null, '0x' + messageHash.toString('hex'), signedData)
})
}
getProvider () {

@ -0,0 +1,16 @@
const EventEmitter = require('events')
class SelectAccount extends EventEmitter {
command (account) {
if (account) {
this.api
.click(`select[data-id="runTabSelectAccount"] [value="${account}"]`)
.perform(() => {
this.emit('complete')
})
} else this.emit('complete')
return this
}
}
module.exports = SelectAccount

@ -20,6 +20,7 @@ module.exports = {
.clickLaunchIcon('solidity')
.testContracts('Untitled.sol', sources[0]['browser/Untitled.sol'], ['Ballot'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c')
.setValue('input[placeholder="bytes32[] proposalNames"]', '["0x48656c6c6f20576f726c64210000000000000000000000000000000000000000"]')
.click('#runTabView button[class^="instanceButton"]')
.waitForElementPresent('.instance:nth-of-type(2)')

@ -11,6 +11,8 @@ module.exports = {
},
'Add Lib Test File': function (browser) {
browser.addFile('Untitled5.sol', sources[0]['browser/Untitled5.sol'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
},
'Test Auto Deploy Lib': function (browser) {
let addressRef

@ -22,6 +22,7 @@ module.exports = {
done()
})
.modalFooterOKClick()
.end()
},
'Publish on Swarm': '' + function (browser) {
browser

@ -13,6 +13,7 @@ module.exports = {
var addressRef
browser.addFile('scenario.json', {content: records})
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('div[class^="cardContainer"] i[class^="arrow"]')
.click('#runTabView .runtransaction')
.waitForElementPresent('.instance:nth-of-type(2)')
@ -68,7 +69,7 @@ var sources = [{'browser/testRecorder.sol': {content: `contract testRecorder {
var records = `{
"accounts": {
"account{0}": "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c"
"account{3}": "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c"
},
"linkReferences": {
"testLib": "created{1512830014773}"
@ -85,7 +86,7 @@ var records = `{
"linkReferences": {},
"inputs": "()",
"type": "constructor",
"from": "account{0}"
"from": "account{3}"
}
},
{
@ -111,7 +112,7 @@ var records = `{
"name": "",
"type": "constructor",
"inputs": "(uint256)",
"from": "account{0}"
"from": "account{3}"
}
},
{
@ -127,7 +128,7 @@ var records = `{
"name": "set",
"inputs": "(uint256,address)",
"type": "function",
"from": "account{0}"
"from": "account{3}"
}
}
],
@ -226,7 +227,7 @@ var records = `{
var scenario = {
'accounts': {
'account{0}': '0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c'
'account{3}': '0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c'
},
'linkReferences': {},
'transactions': [
@ -244,7 +245,7 @@ var scenario = {
'name': '',
'type': 'constructor',
'inputs': '(uint256)',
'from': 'account{0}'
'from': 'account{3}'
}
},
{
@ -259,7 +260,7 @@ var scenario = {
'name': 'set',
'inputs': '(uint256)',
'type': 'function',
'from': 'account{0}'
'from': 'account{3}'
}
}
],

@ -11,7 +11,10 @@ module.exports = {
},
'Test Signature': function (browser) {
let hash, signature
browser.clickLaunchIcon('udapp').signMessage('test message', (h, s) => {
browser
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.signMessage('test message', (h, s) => {
hash = h
signature = s
console.log('hash', hash)

@ -13,6 +13,7 @@ module.exports = {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('receiveAndFallback.sol', sources[0]['browser/receiveAndFallback.sol'], ['CheckSpecials']) // compile
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.selectContract('CheckSpecials')
.createContract('') // deploy
.clickInstance(0)

@ -13,6 +13,7 @@ module.exports = {
'Execute Simple Contract and Test Terminal': function (browser) {
browser.testContracts('Untitled.sol', sources[0]['browser/Untitled.sol'], ['TestContract'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('#runTabView button[class^="instanceButton"]')
.waitForElementPresent('.instance:nth-of-type(2)')
.click('.instance:nth-of-type(2) > div > button')

Loading…
Cancel
Save