Merge pull request #479 from ethereum/slider-bug

Fix Debugger Slider Bug
pull/518/head
yann300 4 years ago committed by GitHub
commit 8f4f9118b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  2. 4
      apps/remix-ide/src/app/tabs/debugger/debuggerUI/VmDebugger.js
  3. 28
      apps/remix-ide/src/app/tabs/debugger/debuggerUI/vmDebugger/SolidityLocals.js
  4. 2
      apps/remix-ide/src/app/tabs/debugger/debuggerUI/vmDebugger/utils/SolidityTypeFormatter.js
  5. 7
      apps/remix-ide/src/app/ui/TreeView.js
  6. 4
      libs/remix-debug/src/debugger/VmDebugger.js
  7. 30
      libs/remix-debug/src/debugger/solidityLocals.js
  8. 4
      libs/remix-debug/src/solidity-decoder/localDecoder.js
  9. 22
      libs/remix-debug/src/solidity-decoder/types/ArrayType.js
  10. 4
      libs/remix-debug/src/solidity-decoder/types/RefType.js
  11. 2
      libs/remix-debug/test/debugger.js

@ -42,7 +42,6 @@ module.exports = {
.waitForElementVisible('*[data-id="slider"]')
.click('*[data-id="slider"]')
.setValue('*[data-id="slider"]', '50')
.pause(2000)
.assert.containsText('*[data-id="solidityLocals"]', 'no locals')
.assert.containsText('*[data-id="stepdetail"]', 'vm trace step:\n92')
},
@ -130,6 +129,25 @@ module.exports = {
.goToVMTraceStep(717)
.pause(5000)
.checkVariableDebug('soliditylocals', localVariable_step717_ABIEncoder) // all locals should be initiaed
},
'Should load more solidity locals array': function (browser: NightwatchBrowser) {
browser.addFile('locals.sol', sources[3]['browser/locals.sol'])
.clickLaunchIcon('udapp')
.createContract('')
.clickInstance(3)
.clickFunction('t - transact (not payable)')
.pause(2000)
.debugTransaction(6)
.waitForElementVisible('*[data-id="slider"]')
.click('*[data-id="slider"]')
.setValue('*[data-id="slider"]', '5000')
.waitForElementPresent('*[data-id="treeViewTogglearray"]')
.click('*[data-id="treeViewTogglearray"]')
.waitForElementPresent('*[data-id="treeViewLoadMore"]')
.click('*[data-id="treeViewLoadMore"]')
.assert.containsText('*[data-id="solidityLocals"]', '149: 0 uint256')
.notContainsText('*[data-id="solidityLocals"]', '150: 0 uint256')
.end()
},
@ -194,6 +212,21 @@ const sources = [
}
}
`}
},
{
'browser/locals.sol': {
content: `
pragma solidity ^0.6.0;
contract test {
function t () public {
uint[] memory array = new uint[](150);
for (uint k = 0; k < 150; k++) {
array[k] = k;
}
}
}
`
}
}
]

@ -83,9 +83,13 @@ function VmDebugger (vmDebuggerLogic) {
this.vmDebuggerLogic.event.register('solidityStateUpdating', this.solidityState.setUpdating.bind(this.solidityState))
this.solidityLocals = new SolidityLocals()
this.solidityLocals.event.register('solidityLocalsLoadMore', (cursor) => {
this.vmDebuggerLogic.event.trigger('solidityLocalsLoadMore', [cursor])
})
this.vmDebuggerLogic.event.register('solidityLocals', this.solidityLocals.update.bind(this.solidityLocals))
this.vmDebuggerLogic.event.register('solidityLocalsMessage', this.solidityLocals.setMessage.bind(this.solidityLocals))
this.vmDebuggerLogic.event.register('solidityLocalsUpdating', this.solidityLocals.setUpdating.bind(this.solidityLocals))
this.vmDebuggerLogic.event.register('solidityLocalsLoadMoreCompleted', this.solidityLocals.loadMore.bind(this.solidityLocals))
this.returnValuesPanel = new DropdownPanel('Return Value', {json: true})
this.returnValuesPanel.data = {}

@ -6,18 +6,28 @@ var yo = require('yo-yo')
class SolidityLocals {
constructor (_parent, _traceManager, _internalTreeCall) {
constructor () {
this.event = new EventManager()
this.basicPanel = new DropdownPanel('Solidity Locals', {
json: true,
formatSelf: solidityTypeFormatter.formatSelf,
extractData: solidityTypeFormatter.extractData
extractData: solidityTypeFormatter.extractData,
loadMore: (cursor) => {
this.event.trigger('solidityLocalsLoadMore', [cursor])
}
})
this.view
this._data = null
}
update (data) {
this.basicPanel.update(data)
this._data = data
this.basicPanel.update(this._data)
}
loadMore (data) {
this._data = this.mergeLocals(data, this._data)
this.basicPanel.update(this._data)
}
setMessage (message) {
@ -28,6 +38,18 @@ class SolidityLocals {
this.basicPanel.setUpdating()
}
mergeLocals (locals1, locals2) {
Object.keys(locals2).map(item => {
if (locals2[item].cursor && (parseInt(locals2[item].cursor) < parseInt(locals1[item].cursor))) {
locals2[item] = {
...locals1[item],
value: [...locals2[item].value, ...locals1[item].value]
}
}
})
return locals2
}
render () {
this.view = yo`<div id='soliditylocals' data-id="solidityLocals">${this.basicPanel.render()}</div>`
return this.view

@ -34,6 +34,8 @@ function extractData (item, parent, key) {
})
ret.isArray = true
ret.self = parent.isArray ? '' : item.type
ret.cursor = item.cursor
ret.hasNext = item.hasNext
} else if (item.type.indexOf('struct') === 0) {
ret.children = Object.keys((item.value || {})).map(function (key) {
return {key: key, value: item.value[key]}

@ -34,6 +34,9 @@ var css = csjs`
.label_value {
min-width: 10%;
}
.cursor_pointer {
cursor: pointer;
}
`
var EventManager = require('../../lib/events')
@ -49,6 +52,7 @@ class TreeView {
this.event = new EventManager()
this.extractData = opts.extractData || this.extractDataDefault
this.formatSelf = opts.formatSelf || this.formatSelfDefault
this.loadMore = opts.loadMore
this.view = null
this.expandPath = []
}
@ -111,6 +115,9 @@ class TreeView {
self.event.trigger('nodeRightClick', [keyPath, data, label, event])
}
li.appendChild(list)
if (data.hasNext) {
list.appendChild(yo`<li><span class="w-100 text-primary ${css.cursor_pointer}" data-id="treeViewLoadMore" onclick="${() => self.loadMore(data.cursor)}">Load more</span></li>`)
}
} else {
caret.style.visibility = 'hidden'
label.oncontextmenu = function (event) {

@ -228,6 +228,10 @@ class VmDebuggerLogic {
listenToSolidityLocalsEvents () {
this.event.register('sourceLocationChanged', this.debuggerSolidityLocals.init.bind(this.debuggerSolidityLocals))
this.event.register('solidityLocalsLoadMore', this.debuggerSolidityLocals.decodeMore.bind(this.debuggerSolidityLocals))
this.debuggerSolidityLocals.event.register('solidityLocalsLoadMoreCompleted', (locals) => {
this.event.trigger('solidityLocalsLoadMoreCompleted', [locals])
})
this.debuggerSolidityLocals.event.register('solidityLocals', (state) => {
this.event.trigger('solidityLocals', [state])
})

@ -15,6 +15,7 @@ class DebuggerSolidityLocals {
}
init (sourceLocation) {
this._sourceLocation = sourceLocation
var decodeTimeout = null
if (!this.storageResolver) {
return this.event.trigger('solidityLocalsMessage', ['storage not ready'])
@ -28,7 +29,7 @@ class DebuggerSolidityLocals {
}, 500)
}
decode (sourceLocation) {
decode (sourceLocation, cursor) {
const self = this
this.event.trigger('solidityLocalsMessage', [''])
this.traceManager.waterfall([
@ -65,12 +66,18 @@ class DebuggerSolidityLocals {
var memory = result[1].value
try {
var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: result[2].value }, this.storageResolver, this.traceManager)
localDecoder.solidityLocals(this.stepManager.currentStepIndex, this.internalTreeCall, stack, memory, storageViewer, sourceLocation).then((locals) => {
if (!locals.error) {
this.event.trigger('solidityLocals', [locals])
}
if (!Object.keys(locals).length) {
this.event.trigger('solidityLocalsMessage', ['no locals'])
localDecoder.solidityLocals(this.stepManager.currentStepIndex, this.internalTreeCall, stack, memory, storageViewer, sourceLocation, cursor).then((locals) => {
if (!cursor) {
if (!locals.error) {
this.event.trigger('solidityLocals', [locals])
}
if (!Object.keys(locals).length) {
this.event.trigger('solidityLocalsMessage', ['no locals'])
}
} else {
if (!locals.error) {
this.event.trigger('solidityLocalsLoadMoreCompleted', [locals])
}
}
})
} catch (e) {
@ -79,6 +86,15 @@ class DebuggerSolidityLocals {
})
}
decodeMore (cursor) {
let decodeTimeout = null
if (!this.storageResolver) return this.event.trigger('solidityLocalsMessage', ['storage not ready'])
if (decodeTimeout) window.clearTimeout(decodeTimeout)
decodeTimeout = setTimeout(() => {
this.decode(this._sourceLocation, cursor)
}, 500)
}
}
module.exports = DebuggerSolidityLocals

@ -1,6 +1,6 @@
'use strict'
async function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storageResolver, currentSourceLocation) {
async function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storageResolver, currentSourceLocation, cursor) {
const scope = internalTreeCall.findScope(vmtraceIndex)
if (!scope) {
const error = { 'message': 'Can\'t display locals. reason: compilation result might not have been provided' }
@ -18,7 +18,7 @@ async function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, st
anonymousIncr++
}
try {
locals[name] = await variable.type.decodeFromStack(variable.stackDepth, stack, memory, storageResolver)
locals[name] = await variable.type.decodeFromStack(variable.stackDepth, stack, memory, storageResolver, cursor)
} catch (e) {
console.log(e)
locals[name] = '<decoding failed - ' + e.message + '>'

@ -72,7 +72,7 @@ class ArrayType extends RefType {
return {value: ret, length: '0x' + size.toString(16), type: this.typeName}
}
decodeFromMemoryInternal (offset, memory) {
decodeFromMemoryInternal (offset, memory, skip) {
const ret = []
let length = this.arraySize
if (this.arraySize === 'dynamic') {
@ -80,12 +80,28 @@ class ArrayType extends RefType {
length = parseInt(length, 16)
offset = offset + 32
}
for (var k = 0; k < length; k++) {
if (isNaN(length)) {
return {
value: '<decoding failed - length is NaN>',
type: this.typeName
}
}
if (!skip) skip = 0
if (skip) offset = offset + (32 * skip)
let limit = length - skip
if (limit > 100) limit = 100
for (var k = 0; k < limit; k++) {
var contentOffset = offset
ret.push(this.underlyingType.decodeFromMemory(contentOffset, memory))
offset += 32
}
return {value: ret, length: '0x' + length.toString(16), type: this.typeName}
return {
value: ret,
length: '0x' + length.toString(16),
type: this.typeName,
cursor: skip + limit,
hasNext: length > (skip + limit)
}
}
}

@ -19,7 +19,7 @@ class RefType {
* @param {Object} - storageResolver
* @return {Object} decoded value
*/
async decodeFromStack (stackDepth, stack, memory, storageResolver) {
async decodeFromStack (stackDepth, stack, memory, storageResolver, cursor) {
if (stack.length - 1 < stackDepth) {
return {error: '<decoding failed - stack underflow ' + stackDepth + '>', type: this.typeName}
}
@ -34,7 +34,7 @@ class RefType {
}
} else if (this.isInMemory()) {
offset = parseInt(offset, 16)
return this.decodeFromMemoryInternal(offset, memory)
return this.decodeFromMemoryInternal(offset, memory, cursor)
} else {
return {error: '<decoding failed - no decoder for ' + this.location + '>', type: this.typeName}
}

@ -257,7 +257,7 @@ function testDebugging (debugManager) {
tape('traceManager.decodeLocalsAt', async (t) => {
t.plan(1)
const tested = JSON.parse('{"proposalNames":{"value":[{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"}],"length":"0x1","type":"bytes32[]"},"p":{"value":"45","type":"uint256"},"addressLocal":{"value":"0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB","type":"address"},"i":{"value":"2","type":"uint256"},"proposalsLocals":{"value":[{"value":{"name":{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"},"voteCount":{"value":"0","type":"uint256"}},"type":"struct Ballot.Proposal"}],"length":"0x1","type":"struct Ballot.Proposal[]"}}')
const tested = JSON.parse('{"proposalNames":{"value":[{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"}],"length":"0x1","type":"bytes32[]","cursor":1,"hasNext":false},"p":{"value":"45","type":"uint256"},"addressLocal":{"value":"0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB","type":"address"},"i":{"value":"2","type":"uint256"},"proposalsLocals":{"value":[{"value":{"name":{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"},"voteCount":{"value":"0","type":"uint256"}},"type":"struct Ballot.Proposal"}],"length":"0x1","type":"struct Ballot.Proposal[]"}}')
try {
const address = debugManager.traceManager.getCurrentCalledAddressAt(330)
const location = await debugManager.sourceLocationFromVMTraceIndex(address, 330)

Loading…
Cancel
Save