diff --git a/apps/remix-ide-e2e/src/tests/pluginManager.spec.ts b/apps/remix-ide-e2e/src/tests/pluginManager.spec.ts index bd2884e4e5..f87bf1269e 100644 --- a/apps/remix-ide-e2e/src/tests/pluginManager.spec.ts +++ b/apps/remix-ide-e2e/src/tests/pluginManager.spec.ts @@ -5,7 +5,7 @@ import init from '../helpers/init' const testData = { pluginName: 'remixIde', pluginDisplayName: 'Remix IDE', - pluginUrl: 'https://zokrates-remix-plugin.netlify.app/' + pluginUrl: 'https://zokrates.github.io/zokrates-remix-plugin/' } module.exports = { diff --git a/apps/remix-ide/src/app/tabs/hardhat-provider.js b/apps/remix-ide/src/app/tabs/hardhat-provider.js index 037117fa85..805bc37e08 100644 --- a/apps/remix-ide/src/app/tabs/hardhat-provider.js +++ b/apps/remix-ide/src/app/tabs/hardhat-provider.js @@ -17,11 +17,13 @@ export default class HardhatProvider extends Plugin { constructor (blockchain) { super(profile) this.provider = null + this.blocked = false // used to block any call when trying to recover after a failed connection. this.blockchain = blockchain } onDeactivation () { this.provider = null + this.blocked = false } hardhatProviderDialogBody () { @@ -39,6 +41,8 @@ export default class HardhatProvider extends Plugin { sendAsync (data) { return new Promise((resolve, reject) => { + if (this.blocked) return reject(new Error('provider unable to connect')) + // If provider is not set, allow to open modal only when provider is trying to connect if (!this.provider) { modalDialogCustom.prompt('Hardhat node request', this.hardhatProviderDialogBody(), 'http://127.0.0.1:8545', (target) => { this.provider = new Web3.providers.HttpProvider(target) @@ -54,9 +58,16 @@ export default class HardhatProvider extends Plugin { sendAsyncInternal (data, resolve, reject) { if (this.provider) { - this.provider[this.provider.sendAsync ? 'sendAsync' : 'send'](data, (error, message) => { + // Check the case where current environment is VM on UI and it still sends RPC requests + // This will be displayed on UI tooltip as 'cannot get account list: Environment Updated !!' + if (this.blockchain.getProvider() !== 'Hardhat Provider' && data.method !== 'net_listening') return reject(new Error('Environment Updated !!')) + this.provider[this.provider.sendAsync ? 'sendAsync' : 'send'](data, async (error, message) => { if (error) { + this.blocked = true + modalDialogCustom.alert('Hardhat Provider', `Error while connecting to the hardhat provider: ${error.message}`) + await this.call('udapp', 'setEnvironmentMode', 'vm') this.provider = null + setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm return reject(error) } resolve(message) diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 26f684e432..45bc5a7421 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -14,7 +14,7 @@ const requiredModules = [ // services + layout views + system views const dependentModules = ['git', 'hardhat'] // module which shouldn't be manually activated (e.g git is activated by remixd) export function isNative (name) { - const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity'] + const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider'] return nativePlugins.includes(name) || requiredModules.includes(name) } diff --git a/libs/remix-debug/src/code/codeManager.ts b/libs/remix-debug/src/code/codeManager.ts index fff30cba15..f0b38ea3d9 100644 --- a/libs/remix-debug/src/code/codeManager.ts +++ b/libs/remix-debug/src/code/codeManager.ts @@ -145,15 +145,38 @@ export class CodeManager { }) } - private retrieveIndexAndTrigger (codeMananger, address, step, code) { + private async retrieveIndexAndTrigger (codeMananger, address, step, code) { let result + let next + const returnInstructionIndexes = [] + const outOfGasInstructionIndexes = [] + try { result = codeMananger.getInstructionIndex(address, step) + next = codeMananger.getInstructionIndex(address, step + 1) + + let values = this.traceManager.getAllStopIndexes() + if (values) { + for (const value of values) { + if (value.address === address) { + returnInstructionIndexes.push({ instructionIndex: this.getInstructionIndex(address, value.index), address }) + } + } + } + + values = this.traceManager.getAllOutofGasIndexes() + if (values) { + for (const value of values) { + if (value.address === address) { + outOfGasInstructionIndexes.push({ instructionIndex: this.getInstructionIndex(address, value.index), address }) + } + } + } } catch (error) { return console.log(error) } try { - codeMananger.event.trigger('changed', [code, address, result]) + codeMananger.event.trigger('changed', [code, address, result, next, returnInstructionIndexes, outOfGasInstructionIndexes]) } catch (e) { console.log('dispatching event failed', e) } diff --git a/libs/remix-debug/src/debugger/VmDebugger.ts b/libs/remix-debug/src/debugger/VmDebugger.ts index 2a90d0ed2c..72a131cfd6 100644 --- a/libs/remix-debug/src/debugger/VmDebugger.ts +++ b/libs/remix-debug/src/debugger/VmDebugger.ts @@ -59,8 +59,8 @@ export class VmDebuggerLogic { } listenToCodeManagerEvents () { - this._codeManager.event.register('changed', (code, address, index) => { - this.event.trigger('codeManagerChanged', [code, address, index]) + this._codeManager.event.register('changed', (code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes) => { + this.event.trigger('codeManagerChanged', [code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes]) }) } diff --git a/libs/remix-debug/src/trace/traceAnalyser.ts b/libs/remix-debug/src/trace/traceAnalyser.ts index ae8957b5ac..74651b228d 100644 --- a/libs/remix-debug/src/trace/traceAnalyser.ts +++ b/libs/remix-debug/src/trace/traceAnalyser.ts @@ -49,6 +49,17 @@ export class TraceAnalyser { this.traceCache.pushReturnValue(index, returnParamsObj) } + if (traceHelper.isReturnInstruction(step) || traceHelper.isStopInstruction(step) || traceHelper.isRevertInstruction(step)) { + this.traceCache.pushStopIndex(index, this.traceCache.currentCall.call.address) + } + + try { + if (parseInt(step.gas) - parseInt(step.gasCost) <= 0 || step.error === 'OutOfGas') { + this.traceCache.pushOutOfGasIndex(index, this.traceCache.currentCall.call.address) + } + } catch (e) { + console.error(e) + } } buildCalldata (index, step, tx, newContext) { diff --git a/libs/remix-debug/src/trace/traceCache.ts b/libs/remix-debug/src/trace/traceCache.ts index 7c2d381ccc..411e8e617c 100644 --- a/libs/remix-debug/src/trace/traceCache.ts +++ b/libs/remix-debug/src/trace/traceCache.ts @@ -5,6 +5,8 @@ const { sha3_256 } = util export class TraceCache { returnValues + stopIndexes + outofgasIndexes currentCall callsTree callsData @@ -24,6 +26,8 @@ export class TraceCache { // ...Changes contains index in the vmtrace of the corresponding changes this.returnValues = {} + this.stopIndexes = [] + this.outofgasIndexes = [] this.currentCall = null this.callsTree = null this.callsData = {} @@ -59,7 +63,7 @@ export class TraceCache { this.currentCall.call.reverted = reverted } var parent = this.currentCall.parent - this.currentCall = parent ? { call: parent.call, parent: parent.parent } : null + if (parent) this.currentCall = { call: parent.call, parent: parent.parent } return } const call = { @@ -78,6 +82,14 @@ export class TraceCache { this.currentCall = { call: call, parent: this.currentCall } } + pushOutOfGasIndex (index, address) { + this.outofgasIndexes.push({ index, address }) + } + + pushStopIndex (index, address) { + this.stopIndexes.push({ index, address }) + } + pushReturnValue (step, value) { this.returnValues[step] = value } diff --git a/libs/remix-debug/src/trace/traceManager.ts b/libs/remix-debug/src/trace/traceManager.ts index 8e78782922..848b3c57aa 100644 --- a/libs/remix-debug/src/trace/traceManager.ts +++ b/libs/remix-debug/src/trace/traceManager.ts @@ -209,6 +209,14 @@ export class TraceManager { return this.trace[stepIndex].pc } + getAllStopIndexes () { + return this.traceCache.stopIndexes + } + + getAllOutofGasIndexes () { + return this.traceCache.outofgasIndexes + } + getReturnValue (stepIndex) { try { this.checkRequestedStep(stepIndex) diff --git a/libs/remix-lib/src/web3Provider/web3VmProvider.ts b/libs/remix-lib/src/web3Provider/web3VmProvider.ts index 59b0e7e909..b5d8ea4732 100644 --- a/libs/remix-lib/src/web3Provider/web3VmProvider.ts +++ b/libs/remix-lib/src/web3Provider/web3VmProvider.ts @@ -138,7 +138,7 @@ export class Web3VmProvider { async txProcessed (data) { const lastOp = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1] if (lastOp) { - lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'thisDESTRUCT' + lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'DESTRUCT' } this.vmTraces[this.processingHash].gas = '0x' + data.gasUsed.toString(16) diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index af3648aa90..7adc8a9312 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -274,7 +274,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
Debugger Configuration
-