Merge branch 'master' into search

pull/2092/head
bunsenstraat 3 years ago committed by GitHub
commit a45c1254b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      apps/remix-ide-e2e/src/commands/goToVMTraceStep.ts
  2. 81
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  3. 16
      apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
  4. 2
      apps/remix-ide/src/remixEngine.js
  5. 2
      libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts
  6. 1
      libs/remix-debug/src/Ethdebugger.ts
  7. 6
      libs/remix-debug/src/debugger/debugger.ts
  8. 9
      libs/remix-debug/src/debugger/stepManager.ts
  9. 2
      libs/remix-debug/src/storage/storageResolver.ts
  10. 5
      libs/remix-lib/README.md
  11. 11
      libs/remix-lib/src/index.ts
  12. 55
      libs/remix-lib/src/web3Provider/dummyProvider.ts
  13. 38
      libs/remix-lib/src/web3Provider/web3Providers.ts
  14. 49
      libs/remix-simulator/src/VmProxy.ts
  15. 40
      libs/remix-simulator/src/vm-context.ts
  16. 4
      libs/remix-ui/debugger-ui/src/lib/button-navigator/button-navigator.css
  17. 9
      libs/remix-ui/debugger-ui/src/lib/button-navigator/button-navigator.tsx
  18. 27
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  19. 15
      libs/remix-ui/debugger-ui/src/lib/slider/slider.tsx
  20. 2
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx

@ -12,6 +12,7 @@ class GoToVmTraceStep extends EventEmitter {
function goToVMtraceStep (browser: NightwatchBrowser, step: number, incr: number, done: VoidFunction) {
browser.execute(function (step) { (document.getElementById('slider') as HTMLInputElement).value = (step - 1).toString() }, [step])
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.pause(1000)
.perform(() => {
done()
})

@ -39,12 +39,9 @@ module.exports = {
'Should debug transaction using slider #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.waitForElementVisible('*[data-id="slider"]')
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '50' }) // It only moves slider to 50 but vm traces are not updated
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.pause(2000)
.click('*[data-id="dropdownPanelSolidityLocals"]')
.waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000)
.goToVMTraceStep(51)
.waitForElementContainsText('*[data-id="solidityLocals"]', 'toast', 60000)
.waitForElementContainsText('*[data-id="solidityLocals"]', '999', 60000)
.waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n51', 60000)
},
@ -159,10 +156,7 @@ module.exports = {
.pause(2000)
.debugTransaction(0)
.waitForElementVisible('*[data-id="slider"]').pause(2000)
// .setValue('*[data-id="slider"]', '5000') // Like this, setValue doesn't work properly for input type = range
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '7450' }).pause(10000) // It only moves slider to 7450 but vm traces are not updated
.setValue('*[data-id="slider"]', new Array(3).fill(browser.Keys.RIGHT_ARROW)) // This will press NEXT 3 times and will update the trace details
.goToVMTraceStep(7453)
.waitForElementPresent('*[data-id="treeViewDivtreeViewItemarray"]')
.click('*[data-id="treeViewDivtreeViewItemarray"]')
.waitForElementPresent('*[data-id="treeViewDivtreeViewLoadMore"]')
@ -210,15 +204,7 @@ module.exports = {
.pause(3000)
.clickLaunchIcon('debugger')
.waitForElementVisible('*[data-id="slider"]')
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '153' }) // It only moves slider to 153 but vm traces are not updated
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.pause(1000)
/*
setting the slider to 5 leads to "vm trace step: 91" for chrome and "vm trace step: 92" for firefox
=> There is something going wrong with the nightwatch API here.
As we are only testing if debugger is active, this is ok to keep that for now.
*/
.goToVMTraceStep(154)
.waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n154', 60000)
},
@ -242,7 +228,22 @@ module.exports = {
.pause(10000)
.checkVariableDebug('soliditylocals', { num: { value: '2', type: 'uint256' } })
.checkVariableDebug('soliditystate', { number: { value: '0', type: 'uint256', constant: false, immutable: false } })
.end()
},
'Should debug reverted transactions #group5': function (browser: NightwatchBrowser) {
browser
.testContracts('reverted.sol', sources[6]['reverted.sol'], ['A', 'B', 'C'])
.clickLaunchIcon('udapp')
.selectContract('A')
.createContract('')
.pause(500)
.clickInstance(0)
.clickFunction('callA - transact (not payable)')
.debugTransaction(1)
.goToVMTraceStep(79)
.waitForElementVisible('*[data-id="debugGoToRevert"]', 60000)
.click('*[data-id="debugGoToRevert"]')
.waitForElementContainsText('*[data-id="asmitems"] div[selected="selected"]', '117 REVERT')
}
}
@ -366,6 +367,46 @@ const sources = [
}
`
}
},
{
'reverted.sol': {
content: `contract A {
B b;
uint p;
constructor () {
b = new B();
}
function callA() public {
p = 123;
try b.callB() {
}
catch (bytes memory reason) {
}
}
}
contract B {
C c;
uint p;
constructor () {
c = new C();
}
function callB() public {
p = 124;
revert("revert!");
c.callC();
}
}
contract C {
uint p;
function callC() public {
p = 125;
}
}`
}
}
]

@ -283,9 +283,7 @@ module.exports = {
.waitForElementVisible('*[data-id="dropdownPanelSolidityLocals"]').pause(1000)
.click('*[data-id="dropdownPanelSolidityLocals"]')
.waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '315' }) // It only moves slider to 315 but vm traces are not updated
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.goToVMTraceStep(316)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'vote(proposal)', 60000)
.pause(5000)
@ -295,9 +293,7 @@ module.exports = {
.scrollAndClick('#Check_winning_proposal_passed')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '1450' })
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.goToVMTraceStep(1451)
.waitForElementContainsText('*[data-id="functionPanel"]', 'equal(a, b, message)', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000)
// remix_test.sol should be opened in editor
@ -307,9 +303,7 @@ module.exports = {
.scrollAndClick('#Check_winning_proposal_again')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '1150' })
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.goToVMTraceStep(1151)
.waitForElementContainsText('*[data-id="functionPanel"]', 'equal(a, b, message)', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000)
.pause(5000)
@ -317,9 +311,7 @@ module.exports = {
.scrollAndClick('#Check_winnin_proposal_with_return_value').pause(5000)
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinninProposalWithReturnValue()', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '320' })
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.goToVMTraceStep(321)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinninProposalWithReturnValue()', 60000)
.clickLaunchIcon('filePanel')
.pause(2000)

@ -15,6 +15,8 @@ export class RemixEngine extends Engine {
if (name === 'hardhat') return { queueTimeout: 60000 * 4 }
if (name === 'localPlugin') return { queueTimeout: 60000 * 4 }
if (name === 'notification') return { queueTimeout: 60000 * 4 }
if (name === 'sourcify') return { queueTimeout: 60000 * 4 }
if (name === 'fetchAndCompile') return { queueTimeout: 60000 * 4 }
return { queueTimeout: 10000 }
}

@ -108,7 +108,7 @@ export class FetchAndCompile extends Plugin {
language: data.metadata.language,
evmVersion: data.metadata.settings.evmVersion,
optimize: data.metadata.settings.optimizer.enabled,
runs: data.metadata.settings.runs
runs: data.metadata.settings.optimizer.runs
}
try {
setTimeout(_ => this.emit('compiling', settings), 0)

@ -11,7 +11,6 @@ import { SolidityProxy, stateDecoder, localDecoder, InternalCallTree } from './s
/**
* Ethdebugger is a wrapper around a few classes that helps debugging a transaction
*
* - Web3Providers - define which environment (web3) the transaction will be retrieved from
* - TraceManager - Load / Analyze the trace and retrieve details of specific test
* - CodeManager - Retrieve loaded byte code and help to resolve AST item from vmtrace index
* - SolidityProxy - Basically used to extract state variable from AST

@ -68,7 +68,10 @@ export class Debugger {
try {
const address = this.debugger.traceManager.getCurrentCalledAddressAt(index)
const compilationResultForAddress = await this.compilationResult(address)
if (!compilationResultForAddress) return
if (!compilationResultForAddress) {
this.event.trigger('newSourceLocation', [null])
return
}
this.debugger.callTree.sourceLocationTracker.getValidSourceLocationFromVMTraceIndex(address, index, compilationResultForAddress.data.contracts).then(async (rawLocation) => {
if (compilationResultForAddress && compilationResultForAddress.data) {
@ -91,6 +94,7 @@ export class Debugger {
})
// })
} catch (error) {
this.event.trigger('newSourceLocation', [null])
return console.log(error)
}
}

@ -51,15 +51,18 @@ export class DebuggerStepManager {
this.traceManager.buildCallPath(index).then((callsPath) => {
this.currentCall = callsPath[callsPath.length - 1]
if (this.currentCall.reverted) {
const revertedReason = this.currentCall.outofgas ? 'outofgas' : ''
const revertedReason = this.currentCall.outofgas ? 'outofgas' : 'reverted'
this.revertionPoint = this.currentCall.return
return this.event.trigger('revertWarning', [revertedReason])
this.event.trigger('revertWarning', [revertedReason])
return
}
for (let k = callsPath.length - 2; k >= 0; k--) {
const parent = callsPath[k]
if (!parent.reverted) continue
if (parent.reverted) {
this.revertionPoint = parent.return
this.event.trigger('revertWarning', ['parenthasthrown'])
return
}
}
this.event.trigger('revertWarning', [''])
}).catch((error) => {

@ -133,7 +133,7 @@ export class StorageResolver {
resolve([{}, null])
} else {
this.web3.debug.storageRangeAt(
tx.blockHash, tx.hash,
tx.blockHash, tx.transactionIndex,
address,
start,
maxSize,

@ -23,11 +23,6 @@
ui: uiHelper,
compiler: compilerHelper
},
vm: {
Web3Providers: Web3Providers,
DummyProvider: DummyProvider,
Web3VMProvider: Web3VmProvider
},
Storage: Storage,
util: util,
execution: {

@ -2,9 +2,6 @@ import { EventManager } from './eventManager'
import * as uiHelper from './helpers/uiHelper'
import * as compilerHelper from './helpers/compilerHelper'
import * as util from './util'
import { Web3Providers } from './web3Provider/web3Providers'
import { DummyProvider } from './web3Provider/dummyProvider'
import { Web3VmProvider } from './web3Provider/web3VmProvider'
import { Storage } from './storage'
import { EventsDecoder } from './execution/eventsDecoder'
import * as txExecution from './execution/txExecution'
@ -18,6 +15,7 @@ import * as typeConversion from './execution/typeConversion'
import { TxRunnerVM } from './execution/txRunnerVM'
import { TxRunnerWeb3 } from './execution/txRunnerWeb3'
import * as txResultHelper from './helpers/txResultHelper'
export { ConsoleLogs } from './helpers/hhconsoleSigs'
export { ICompilerApi, ConfigurationSettings } from './types/ICompilerApi'
export { QueryParams } from './query-params'
@ -26,11 +24,6 @@ const helpers = {
compiler: compilerHelper,
txResultHelper
}
const vm = {
Web3Providers: Web3Providers,
DummyProvider: DummyProvider,
Web3VMProvider: Web3VmProvider
}
const execution = {
EventsDecoder: EventsDecoder,
txExecution: txExecution,
@ -44,4 +37,4 @@ const execution = {
LogsManager,
forkAt
}
export { EventManager, helpers, vm, Storage, util, execution }
export { EventManager, helpers, Storage, util, execution }

@ -1,55 +0,0 @@
export class DummyProvider {
eth
debug
providers
currentProvider
constructor () {
this.eth = {}
this.debug = {}
this.eth.getCode = (address, cb) => { return this.getCode(address, cb) }
this.eth.getTransaction = (hash, cb) => { return this.getTransaction(hash, cb) }
this.eth.getTransactionFromBlock = (blockNumber, txIndex, cb) => { return this.getTransactionFromBlock(blockNumber, txIndex, cb) }
this.eth.getBlockNumber = (cb) => { return this.getBlockNumber(cb) }
this.debug.traceTransaction = (hash, options, cb) => { return this.traceTransaction(hash, options, cb) }
this.debug.storageRangeAt = (blockNumber, txIndex, address, start, end, maxLength, cb) => { return this.storageRangeAt(blockNumber, txIndex, address, start, end, maxLength, cb) }
this.providers = { HttpProvider: function (url) {} }
this.currentProvider = { host: '' }
}
getCode (address, cb) {
cb(null, '')
}
setProvider (provider) {}
traceTransaction (txHash, options, cb) {
if (cb) {
cb(null, {})
}
return {}
}
storageRangeAt (blockNumber, txIndex, address, start, end, maxLength, cb) {
if (cb) {
cb(null, {})
}
return {}
}
getBlockNumber (cb) { cb(null, '') }
getTransaction (txHash, cb) {
if (cb) {
cb(null, {})
}
return {}
}
getTransactionFromBlock (blockNumber, txIndex, cb) {
if (cb) {
cb(null, {})
}
return {}
}
}

@ -1,38 +0,0 @@
import { Web3VmProvider } from './web3VmProvider'
import { loadWeb3, extendWeb3 } from '../init'
export class Web3Providers {
modes
constructor () {
this.modes = {}
}
addProvider (type, obj) {
if (type === 'INTERNAL') {
const web3 = loadWeb3()
this.addWeb3(type, web3)
} else if (type === 'vm') {
this.addVM(type, obj)
} else {
extendWeb3(obj)
this.addWeb3(type, obj)
}
}
get (type, cb) {
if (this.modes[type]) {
return cb(null, this.modes[type])
}
cb('error: this provider has not been setup (' + type + ')', null)
}
addWeb3 (type, web3) {
this.modes[type] = web3
}
addVM (type, vm) {
const vmProvider = new Web3VmProvider()
vmProvider.setVM(vm)
this.modes[type] = vmProvider
}
}

@ -1,12 +1,16 @@
import { hexListFromBNs, formatMemory } from '../util'
import { normalizeHexAddress } from '../helpers/uiHelper'
import { ConsoleLogs } from '../helpers/hhconsoleSigs'
import { util } from '@remix-project/remix-lib'
const { hexListFromBNs, formatMemory } = util
import { helpers } from '@remix-project/remix-lib'
const { normalizeHexAddress } = helpers.ui
import { ConsoleLogs } from '@remix-project/remix-lib'
import { toChecksumAddress, BN, bufferToHex, Address } from 'ethereumjs-util'
import Web3 from 'web3'
import { ethers } from 'ethers'
import { VMContext } from './vm-context'
export class Web3VmProvider {
web3
export class VmProxy {
vmContext: VMContext
web3: Web3
vm
vmTraces
txs
@ -38,7 +42,8 @@ export class Web3VmProvider {
blocks
latestBlockNumber
constructor () {
constructor (vmContext: VMContext) {
this.vmContext = vmContext
this.web3 = new Web3()
this.vm = null
this.vmTraces = {}
@ -66,15 +71,15 @@ export class Web3VmProvider {
this.lastProcessedStorageTxHash = {}
this.sha3Preimages = {}
// util
this.sha3 = (...args) => this.web3.utils.sha3(...args)
this.toHex = (...args) => this.web3.utils.toHex(...args)
this.toAscii = (...args) => this.web3.utils.hexToAscii(...args)
this.fromAscii = (...args) => this.web3.utils.asciiToHex(...args)
this.fromDecimal = (...args) => this.web3.utils.numberToHex(...args)
this.fromWei = (...args) => this.web3.utils.fromWei(...args)
this.toWei = (...args) => this.web3.utils.toWei(...args)
this.toBigNumber = (...args) => this.web3.utils.toBN(...args)
this.isAddress = (...args) => this.web3.utils.isAddress(...args)
this.sha3 = (...args) => this.web3.utils.sha3.apply(this, args)
this.toHex = (...args) => this.web3.utils.toHex.apply(this, args)
this.toAscii = (...args) => this.web3.utils.toAscii.apply(this, args)
this.fromAscii = (...args) => this.web3.utils.fromAscii.apply(this, args)
this.fromDecimal = (...args) => this.web3.utils.fromDecimal.apply(this, args)
this.fromWei = (...args) => this.web3.utils.fromWei.apply(this, args)
this.toWei = (...args) => this.web3.utils.toWei.apply(this, args)
this.toBigNumber = (...args) => this.web3.utils.toBN.apply(this, args)
this.isAddress = (...args) => this.web3.utils.isAddress.apply(this, args)
this.utils = Web3.utils || []
this.txsMapBlock = {}
this.blocks = {}
@ -289,16 +294,22 @@ export class Web3VmProvider {
}
}
storageRangeAt (blockNumber, txIndex, address, start, maxLength, cb) { // txIndex is the hash in the case of the VM
storageRangeAt (blockNumber, txIndex, address, start, maxLength, cb) {
// we don't use the range params here
address = toChecksumAddress(address)
let txHash
if (txIndex === 'latest') {
txIndex = this.lastProcessedStorageTxHash[address]
txHash = this.lastProcessedStorageTxHash[address]
} else {
const block = this.vmContext.blocks[blockNumber]
txHash = '0x' + block.transactions[txIndex].hash().toString('hex')
}
if (this.storageCache[txIndex] && this.storageCache[txIndex][address]) {
const storage = this.storageCache[txIndex][address]
if (this.storageCache[txHash] && this.storageCache[txHash][address]) {
const storage = this.storageCache[txHash][address]
return cb(null, {
storage: JSON.parse(JSON.stringify(storage)),
nextKey: null

@ -2,11 +2,15 @@
'use strict'
import Web3 from 'web3'
import { rlp, keccak, bufferToHex } from 'ethereumjs-util'
import { vm as remixLibVm, execution } from '@remix-project/remix-lib'
import { execution } from '@remix-project/remix-lib'
const { LogsManager } = execution
import { VmProxy } from './VmProxy'
import VM from '@ethereumjs/vm'
import Common from '@ethereumjs/common'
import StateManager from '@ethereumjs/vm/dist/state/stateManager'
import { StorageDump } from '@ethereumjs/vm/dist/state/interface'
import { Block } from '@ethereumjs/block'
import { Transaction } from '@ethereumjs/tx'
/*
extend vm state manager and instanciate VM
@ -75,6 +79,13 @@ class StateManagerCommonStorageDump extends StateManager {
}
}
export type CurrentVm = {
vm: VM,
web3vm: VmProxy,
stateManager: StateManagerCommonStorageDump,
common: Common
}
/*
trigger contextChanged, web3EndpointChanged
*/
@ -82,15 +93,14 @@ export class VMContext {
currentFork: string
blockGasLimitDefault: number
blockGasLimit: number
customNetWorks
blocks
latestBlockNumber
blockByTxHash
txByHash
currentVm
web3vm
logsManager
exeResults
blocks: Record<string, Block>
latestBlockNumber: string
blockByTxHash: Record<string, Block>
txByHash: Record<string, Transaction>
currentVm: CurrentVm
web3vm: VmProxy
logsManager: any // LogsManager
exeResults: Record<string, Transaction>
constructor (fork?) {
this.blockGasLimitDefault = 4300000
@ -98,11 +108,11 @@ export class VMContext {
this.currentFork = fork || 'london'
this.currentVm = this.createVm(this.currentFork)
this.blocks = {}
this.latestBlockNumber = 0
this.latestBlockNumber = "0x0"
this.blockByTxHash = {}
this.txByHash = {}
this.exeResults = {}
this.logsManager = new execution.LogsManager()
this.logsManager = new LogsManager()
}
createVm (hardfork) {
@ -115,7 +125,9 @@ export class VMContext {
allowUnlimitedContractSize: true
})
const web3vm = new remixLibVm.Web3VMProvider()
// VmProxy and VMContext are very intricated.
// VmProxy is used to track the EVM execution (to listen on opcode execution, in order for instance to generate the VM trace)
const web3vm = new VmProxy(this)
web3vm.setVM(vm)
return { vm, web3vm, stateManager, common }
}
@ -140,7 +152,7 @@ export class VMContext {
return this.currentVm
}
addBlock (block) {
addBlock (block: Block) {
let blockNumber = '0x' + block.header.number.toString('hex')
if (blockNumber === '0x') {
blockNumber = '0x0'

@ -20,3 +20,7 @@
}
.navigator:hover {
}
.cursorPointerRemixDebugger {
cursor: pointer;
}

@ -65,11 +65,10 @@ export const ButtonNavigation = ({ stepOverBack, stepIntoBack, stepIntoForward,
<button className='btn btn-primary btn-sm navigator jumpButton fas fa-step-forward' id='jumpnextbreakpoint' data-id="buttonNavigatorJumpNextBreakpoint" title='Jump to the next breakpoint' onClick={() => { jumpNextBreakpoint && jumpNextBreakpoint() }} disabled={state.jumpNextBreakpointDisabled}></button>
</div>
<div id='reverted' style={{ display: revertedReason === '' ? 'none' : 'block' }}>
<button id='jumptoexception' title='Jump to exception' className='btn btn-danger btn-sm navigator button fas fa-exclamation-triangle' onClick={() => { jumpToException && jumpToException() }} disabled={state.jumpOutDisabled}>
</button>
<span>State changes made during this call will be reverted.</span>
<span id='outofgas' style={{ display: revertedReason === 'outofgas' ? 'inline' : 'none' }}>This call will run out of gas.</span>
<span id='parenthasthrown' style={{ display: revertedReason === 'parenthasthrown' ? 'inline' : 'none' }}>The parent call will throw an exception</span>
<span className='text-warning'>This call has reverted, state changes made during the call will be reverted.</span>
<span className='text-warning' id='outofgas' style={{ display: revertedReason === 'outofgas' ? 'inline' : 'none' }}>This call will run out of gas.</span>
<span className='text-warning' id='parenthasthrown' style={{ display: revertedReason === 'parenthasthrown' ? 'inline' : 'none' }}>The parent call will throw an exception</span>
<div className='text-warning'>Click <u data-id="debugGoToRevert" className="cursorPointerRemixDebugger" role="button" onClick={() => { jumpToException && jumpToException() }}>here</u> to jump where the call reverted.</div>
</div>
</div>
)

@ -32,7 +32,8 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
toastMessage: '',
validationError: '',
txNumberIsEmpty: true,
isLocalNodeUsed: false
isLocalNodeUsed: false,
sourceLocationStatus: ''
})
useEffect(() => {
@ -87,7 +88,13 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
})
debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources, address) => {
if (!lineColumnPos) return
if (!lineColumnPos) {
await debuggerModule.discardHighlight()
setState(prevState => {
return { ...prevState, sourceLocationStatus: 'Source location not available.' }
})
return
}
const contracts = await debuggerModule.fetchContractAndCompile(
address || currentReceipt.contractAddress || currentReceipt.to,
currentReceipt)
@ -113,6 +120,9 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
}
}
if (path) {
setState(prevState => {
return { ...prevState, sourceLocationStatus: '' }
})
await debuggerModule.discardHighlight()
await debuggerModule.highlight(lineColumnPos, path)
}
@ -138,6 +148,12 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
const unloadRequested = (blockNumber, txIndex, tx) => {
unLoad()
setState(prevState => {
return {
...prevState,
sourceLocationStatus: ''
}
})
}
const unLoad = () => {
@ -168,7 +184,8 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
setState(prevState => {
return {
...prevState,
txNumber: txNumber
txNumber: txNumber,
sourceLocationStatus: ''
}
})
if (!isValidHash(txNumber)) {
@ -266,7 +283,8 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
return {
...prevState,
validationError: '',
txNumber: txHash
txNumber: txHash,
sourceLocationStatus: ''
}
})
startDebugging(null, txHash, null, web3)
@ -315,6 +333,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
{ state.validationError && <span className="w-100 py-1 text-danger validationError">{state.validationError}</span> }
</div>
<TxBrowser requestDebug={ requestDebug } unloadRequested={ unloadRequested } updateTxNumberFlag={ updateTxNumberFlag } transactionNumber={ state.txNumber } debugging={ state.debugging } />
{ state.debugging && state.sourceLocationStatus && <div className="text-warning"><i className="fas fa-exclamation-triangle" aria-hidden="true"></i> {state.sourceLocationStatus}</div> }
{ state.debugging && <StepManager stepManager={ stepManager } /> }
{ state.debugging && <VmDebuggerHead vmDebugger={ vmDebugger } /> }
</div>

@ -1,10 +1,12 @@
import React, { useState, useEffect } from 'react' // eslint-disable-line
import React, { useState, useEffect, useRef } from 'react' // eslint-disable-line
export const Slider = ({ jumpTo, sliderValue, traceLength }) => {
const [state, setState] = useState({
currentValue: 0
})
const onChangeId = useRef(null)
useEffect(() => {
setValue(sliderValue)
}, [sliderValue])
@ -18,9 +20,16 @@ export const Slider = ({ jumpTo, sliderValue, traceLength }) => {
}
const handleChange = (e) => {
const value = parseInt(e.target.value)
if (onChangeId.current) {
window.clearTimeout(onChangeId.current)
}
((value) => {
onChangeId.current = setTimeout(() => {
console.log(value)
value = parseInt(value)
setValue(value)
}, 100)
})(e.target.value)
}
return (

@ -125,7 +125,7 @@ export const AssemblyItems = ({ registerEvent }) => {
<div className="border rounded px-1 mt-1 bg-light">
<div className='dropdownpanel'>
<div className='dropdowncontent'>
<div className="pl-2 my-1 small instructions" id='asmitems' ref={asmItemsRef}>
<div className="pl-2 my-1 small instructions" data-id="asmitems" id='asmitems' ref={asmItemsRef}>
{
assemblyItems.display.map((item, i) => {
return <div className="px-1" key={i} ref={ref => { refs.current[i] = ref }}><span>{item}</span></div>

Loading…
Cancel
Save