diff --git a/package.json b/package.json
index a2a6684c51..1981fed635 100644
--- a/package.json
+++ b/package.json
@@ -21,13 +21,16 @@
"devDependencies": {
"babel-preset-react": "^6.5.0",
"babelify": "^7.2.0",
+ "nightwatch": "^0.9.4",
"standard": "^7.0.1",
- "standard-reporter": "^1.0.5"
+ "standard-reporter": "^1.0.5",
+ "tape": "^4.6.0"
},
"scripts": {
"start_node": "eth --rpccorsdomain \"*\" -j -v 0",
"build": "mkdir -p build; browserify -t [ babelify --presets [ react ] ] src/index.js -o build/app.js",
- "test" : "standard"
+ "test": "standard && tape ./test/tests.js",
+ "serve": "http-server ."
},
"repository": {
"type": "git",
@@ -42,7 +45,8 @@
"standard": {
"ignore": [
"node_modules/*",
- "build/*"
+ "build/*",
+ "test/resources/*"
]
}
}
diff --git a/src/codeManager.js b/src/code/codeManager.js
similarity index 93%
rename from src/codeManager.js
rename to src/code/codeManager.js
index da98f3f307..029e225ea5 100644
--- a/src/codeManager.js
+++ b/src/code/codeManager.js
@@ -1,8 +1,8 @@
'use strict'
-var traceManagerUtil = require('./traceManagerUtil')
+var traceHelper = require('../helpers/traceHelper')
var codeResolver = require('./codeResolver')
-var util = require('./util')
-var EventManager = require('./eventManager')
+var util = require('../helpers/global')
+var EventManager = require('../lib/eventManager')
/*
resolve contract code referenced by vmtrace in order to be used by asm listview.
@@ -20,6 +20,7 @@ function CodeManager (_web3, _traceManager) {
this.traceManager = _traceManager
this.currentAddress = ''
codeResolver.setWeb3(_web3)
+ this.codeResolver = codeResolver
}
CodeManager.prototype.resolveStep = function (stepIndex, tx) {
@@ -42,7 +43,7 @@ CodeManager.prototype.resolveStep = function (stepIndex, tx) {
CodeManager.prototype.ensureCodeLoaded = function (address, currentStep, tx) {
var self = this
if (address !== this.currentAddress) {
- if (traceManagerUtil.isContractCreation(address)) {
+ if (traceHelper.isContractCreation(address)) {
this.traceManager.getContractCreationCode(address, function (error, hexCode) {
// contract creation
if (error) {
diff --git a/src/codeResolver.js b/src/code/codeResolver.js
similarity index 100%
rename from src/codeResolver.js
rename to src/code/codeResolver.js
diff --git a/src/codeUtils.js b/src/code/codeUtils.js
similarity index 100%
rename from src/codeUtils.js
rename to src/code/codeUtils.js
diff --git a/src/opcodes.js b/src/code/opcodes.js
similarity index 100%
rename from src/opcodes.js
rename to src/code/opcodes.js
diff --git a/src/debugger.js b/src/debugger.js
index 84709b7374..8baa0b8a9a 100644
--- a/src/debugger.js
+++ b/src/debugger.js
@@ -4,8 +4,8 @@ var TxBrowser = require('./txBrowser')
var StepManager = require('./stepManager')
var VmDebugger = require('./vmDebugger')
var style = require('./basicStyles')
-var util = require('./util')
-var EventManager = require('./eventManager')
+var util = require('./helpers/global')
+var EventManager = require('./lib/eventManager')
module.exports = React.createClass({
ethDebuggerSelectedItem: -1,
diff --git a/src/util.js b/src/helpers/global.js
similarity index 100%
rename from src/util.js
rename to src/helpers/global.js
diff --git a/src/helpers/init.js b/src/helpers/init.js
new file mode 100644
index 0000000000..e4c93ae891
--- /dev/null
+++ b/src/helpers/init.js
@@ -0,0 +1,19 @@
+'use strict'
+var Web3 = require('web3')
+var Web3Admin = require('../util/web3Admin')
+var TraceManager = require('../trace/traceManager')
+var CodeManager = require('../code/codeManager')
+
+module.exports = {
+ loadContext: function () {
+ var web3 = new Web3()
+ web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'))
+ Web3Admin.extend(web3)
+ var traceManager = new TraceManager(web3)
+ return {
+ web3: web3,
+ traceManager: traceManager,
+ codeManager: new CodeManager(web3, traceManager)
+ }
+ }
+}
diff --git a/src/traceManagerUtil.js b/src/helpers/traceHelper.js
similarity index 100%
rename from src/traceManagerUtil.js
rename to src/helpers/traceHelper.js
diff --git a/src/helpers/ui.js b/src/helpers/ui.js
new file mode 100644
index 0000000000..615c9959ce
--- /dev/null
+++ b/src/helpers/ui.js
@@ -0,0 +1,35 @@
+'use strict'
+module.exports = {
+ formatMemory: function (mem, width) {
+ var ret = ''
+ if (!mem) {
+ return ret
+ }
+
+ if (!mem.substr) {
+ mem = mem.join('') // geth returns an array, eth return raw string
+ }
+
+ for (var k = 0; k < mem.length; k += (width * 2)) {
+ var memory = mem.substr(k, width * 2)
+ var content = this.tryConvertAsciiFormat(memory)
+ ret += '0x' + k.toString(16) + ' ' + content.raw + ' ' + content.ascii + '\n'
+ }
+ return ret
+ },
+
+ tryConvertAsciiFormat: function (memorySlot) {
+ var ret = { ascii: '', raw: '' }
+ for (var k = 0; k < memorySlot.length; k += 2) {
+ var raw = memorySlot.substr(k, 2)
+ var ascii = String.fromCharCode(parseInt(raw, 16))
+ ascii = ascii.replace(/\W/g, '?')
+ if (ascii === '') {
+ ascii = '?'
+ }
+ ret.ascii += ascii
+ ret.raw += ' ' + raw
+ }
+ return ret
+ }
+}
diff --git a/src/index.js b/src/index.js
index 3b970a9867..a3b608a91f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,26 +1,10 @@
'use strict'
var ReactDOM = require('react-dom')
var React = require('react')
-var Web3 = require('web3')
-var Web3Admin = require('./web3Admin')
-var TraceManager = require('./traceManager')
-var CodeManager = require('./codeManager')
-
-function loadContext () {
- var web3 = new Web3()
- web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'))
- Web3Admin.extend(web3)
- var traceManager = new TraceManager(web3)
- return {
- web3: web3,
- traceManager: traceManager,
- codeManager: new CodeManager(web3, traceManager)
- }
-}
-
+var util = require('./helpers/init')
var Debugger = require('./debugger')
ReactDOM.render(
-
+ vmtracestep + | ++ {this.state.vmTraceStep} + | +
step @@ -81,6 +90,10 @@ module.exports = React.createClass({ this.context.root.register('indexChanged', this, function (index) { if (index < 0) return + self.setState({ + vmTraceStep: index + }) + self.context.traceManager.getCurrentStep(index, function (error, step) { if (error) { console.log(error) diff --git a/src/traceAnalyser.js b/src/trace/traceAnalyser.js similarity index 77% rename from src/traceAnalyser.js rename to src/trace/traceAnalyser.js index 2e7f67a9c4..b482ae86d3 100644 --- a/src/traceAnalyser.js +++ b/src/trace/traceAnalyser.js @@ -1,5 +1,5 @@ 'use strict' -var traceManagerUtil = require('./traceManagerUtil') +var traceHelper = require('../helpers/traceHelper') function TraceAnalyser (_cache) { this.traceCache = _cache @@ -18,7 +18,7 @@ TraceAnalyser.prototype.analyse = function (trace, tx, callback) { callStack: callStack.slice(0) }) - if (traceManagerUtil.isContractCreation(tx.to)) { + if (traceHelper.isContractCreation(tx.to)) { this.traceCache.pushContractCreation(tx.to, tx.input) } @@ -45,17 +45,17 @@ TraceAnalyser.prototype.buildMemory = function (index, step) { } TraceAnalyser.prototype.buildStorage = function (index, step, context) { - if (traceManagerUtil.newContextStorage(step)) { - var calledAddress = traceManagerUtil.resolveCalledAddress(index, this.trace) + if (traceHelper.newContextStorage(step)) { + var calledAddress = traceHelper.resolveCalledAddress(index, this.trace) if (calledAddress) { context.currentStorageAddress = calledAddress } else { console.log('unable to build storage changes. ' + index + ' does not match with a CALL. storage changes will be corrupted') } this.traceCache.pushStoreChanges(index + 1, context.currentStorageAddress) - } else if (traceManagerUtil.isSSTOREInstruction(step)) { + } else if (traceHelper.isSSTOREInstruction(step)) { this.traceCache.pushStoreChanges(index + 1, context.currentStorageAddress, step.stack[step.stack.length - 1], step.stack[step.stack.length - 2]) - } else if (traceManagerUtil.isReturnInstruction(step)) { + } else if (traceHelper.isReturnInstruction(step)) { context.currentStorageAddress = context.previousStorageAddress this.traceCache.pushStoreChanges(index + 1, context.currentStorageAddress) } @@ -63,14 +63,14 @@ TraceAnalyser.prototype.buildStorage = function (index, step, context) { } TraceAnalyser.prototype.buildDepth = function (index, step, callStack) { - if (traceManagerUtil.isCallInstruction(step) && !traceManagerUtil.isCallToPrecompiledContract(index, this.trace)) { - if (traceManagerUtil.isCreateInstruction(step)) { - var contractToken = traceManagerUtil.contractCreationToken(index) + if (traceHelper.isCallInstruction(step) && !traceHelper.isCallToPrecompiledContract(index, this.trace)) { + if (traceHelper.isCreateInstruction(step)) { + var contractToken = traceHelper.contractCreationToken(index) callStack.push(contractToken) var lastMemoryChange = this.traceCache.memoryChanges[this.traceCache.memoryChanges.length - 1] this.traceCache.pushContractCreationFromMemory(index, contractToken, this.trace, lastMemoryChange) } else { - var newAddress = traceManagerUtil.resolveCalledAddress(index, this.trace) + var newAddress = traceHelper.resolveCalledAddress(index, this.trace) if (newAddress) { callStack.push(newAddress) } else { @@ -81,7 +81,7 @@ TraceAnalyser.prototype.buildDepth = function (index, step, callStack) { this.traceCache.pushCallStack(index + 1, { callStack: callStack.slice(0) }) - } else if (traceManagerUtil.isReturnInstruction(step)) { + } else if (traceHelper.isReturnInstruction(step)) { callStack.pop() this.traceCache.pushCallChanges(step, index + 1) this.traceCache.pushCallStack(index + 1, { diff --git a/src/traceCache.js b/src/trace/traceCache.js similarity index 100% rename from src/traceCache.js rename to src/trace/traceCache.js diff --git a/src/traceManager.js b/src/trace/traceManager.js similarity index 92% rename from src/traceManager.js rename to src/trace/traceManager.js index 8c33bdf6c4..b7ab9a32bf 100644 --- a/src/traceManager.js +++ b/src/trace/traceManager.js @@ -3,7 +3,7 @@ var TraceAnalyser = require('./traceAnalyser') var TraceRetriever = require('./traceRetriever') var TraceCache = require('./traceCache') var TraceStepManager = require('./traceStepManager') -var traceManagerUtil = require('./traceManagerUtil') +var traceHelper = require('../helpers/traceHelper') function TraceManager (_web3) { this.web3 = _web3 @@ -32,12 +32,13 @@ TraceManager.prototype.resolveTrace = function (tx, callback) { self.trace = result.structLogs self.traceAnalyser.analyse(result.structLogs, tx, function (error, result) { if (error) { + self.isLoading = false console.log(error) callback(false) } else { + self.isLoading = false callback(true) } - self.isLoading = false }) } else { console.log(tx.hash + ' is not a contract invokation or contract creation.') @@ -74,7 +75,7 @@ TraceManager.prototype.getStorageAt = function (stepIndex, tx, callback) { if (check) { return callback(check, null) } - var stoChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.storageChanges) + var stoChange = traceHelper.findLowerBound(stepIndex, this.traceCache.storageChanges) if (stoChange === undefined) return callback('no storage found', null) var self = this if (this.traceRetriever.debugStorageAtAvailable()) { @@ -98,7 +99,7 @@ TraceManager.prototype.getCallDataAt = function (stepIndex, callback) { if (check) { return callback(check, null) } - var callDataChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callDataChanges) + var callDataChange = traceHelper.findLowerBound(stepIndex, this.traceCache.callDataChanges) if (callDataChange === undefined) return callback('no calldata found', null) callback(null, [this.trace[callDataChange].calldata]) } @@ -108,7 +109,7 @@ TraceManager.prototype.getCallStackAt = function (stepIndex, callback) { if (check) { return callback(check, null) } - var callStackChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callChanges) + var callStackChange = traceHelper.findLowerBound(stepIndex, this.traceCache.callChanges) if (callStackChange === undefined) return callback('no callstack found', null) callback(null, this.traceCache.callStack[callStackChange].callStack) } @@ -133,7 +134,7 @@ TraceManager.prototype.getLastCallChangeSince = function (stepIndex, callback) { if (check) { return callback(check, null) } - var callChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callChanges) + var callChange = traceHelper.findLowerBound(stepIndex, this.traceCache.callChanges) if (callChange === undefined) { callback(null, 0) } else { @@ -179,7 +180,7 @@ TraceManager.prototype.getMemoryAt = function (stepIndex, callback) { if (check) { return callback(check, null) } - var lastChanges = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.memoryChanges) + var lastChanges = traceHelper.findLowerBound(stepIndex, this.traceCache.memoryChanges) if (lastChanges === undefined) return callback('no memory found', null) callback(null, this.trace[lastChanges].memory) } @@ -225,7 +226,7 @@ TraceManager.prototype.getRemainingGas = function (stepIndex, callback) { } TraceManager.prototype.isCreationStep = function (stepIndex) { - return traceManagerUtil.isCreateInstruction(stepIndex, this.trace) + return traceHelper.isCreateInstruction(this.trace[stepIndex]) } // step section diff --git a/src/traceRetriever.js b/src/trace/traceRetriever.js similarity index 90% rename from src/traceRetriever.js rename to src/trace/traceRetriever.js index 2c2956c34f..88859facbb 100644 --- a/src/traceRetriever.js +++ b/src/trace/traceRetriever.js @@ -1,5 +1,6 @@ 'use strict' -var traceManagerUtil = require('./traceManagerUtil') +var traceHelper = require('../helpers/traceHelper') + function TraceRetriever (_web3) { this.web3 = _web3 this.storages = {} // contains all intial storage (by addresses) @@ -18,7 +19,7 @@ TraceRetriever.prototype.getTrace = function (txHash, callback) { } TraceRetriever.prototype.getStorage = function (tx, address, callback) { - if (traceManagerUtil.isContractCreation(address)) { + if (traceHelper.isContractCreation(address)) { callback(null, {}) } else if (this.storages[address]) { callback(null, this.storages[address]) diff --git a/src/traceStepManager.js b/src/trace/traceStepManager.js similarity index 92% rename from src/traceStepManager.js rename to src/trace/traceStepManager.js index 74fb033622..5f20aa25d2 100644 --- a/src/traceStepManager.js +++ b/src/trace/traceStepManager.js @@ -1,5 +1,5 @@ 'use strict' -var traceManagerUtil = require('./traceManagerUtil') +var traceHelper = require('../helpers/traceHelper') function TraceStepManager (_traceAnalyser) { this.traceAnalyser = _traceAnalyser @@ -7,12 +7,12 @@ function TraceStepManager (_traceAnalyser) { TraceStepManager.prototype.isCallInstruction = function (index) { var state = this.traceAnalyser.trace[index] - return traceManagerUtil.isCallInstruction(state) + return traceHelper.isCallInstruction(state) } TraceStepManager.prototype.isReturnInstruction = function (index) { var state = this.traceAnalyser.trace[index] - return traceManagerUtil.isReturnInstruction(state) + return traceHelper.isReturnInstruction(state) } TraceStepManager.prototype.findStepOverBack = function (currentStep) { diff --git a/src/txBrowser.js b/src/txBrowser.js index f4ff916b9a..68efe933ed 100644 --- a/src/txBrowser.js +++ b/src/txBrowser.js @@ -1,7 +1,7 @@ 'use strict' var React = require('react') var style = require('./basicStyles') -var traceManagerUtil = require('./traceManagerUtil') +var traceHelper = require('./helpers/traceHelper') module.exports = React.createClass({ contextTypes: { @@ -29,9 +29,10 @@ module.exports = React.createClass({ } else { tx = this.context.web3.eth.getTransactionFromBlock(this.state.blockNumber, this.state.txNumber) } + console.log(JSON.stringify(tx)) if (tx) { if (!tx.to) { - tx.to = traceManagerUtil.contractCreationToken('0') + tx.to = traceHelper.contractCreationToken('0') } this.setState({from: tx.from, to: tx.to, hash: tx.hash}) this.props.onNewTxRequested(this.state.blockNumber, parseInt(this.state.txNumber), tx) diff --git a/src/web3Admin.js b/src/util/web3Admin.js similarity index 100% rename from src/web3Admin.js rename to src/util/web3Admin.js diff --git a/test-browser/index.js b/test-browser/index.js new file mode 100644 index 0000000000..7899577b06 --- /dev/null +++ b/test-browser/index.js @@ -0,0 +1,7 @@ +module.exports = { + 'Page Load': function (browser) { + browser + .url('http://127.0.0.1:8080') + .end() + } +} diff --git a/test/TestTraceRetriever.js b/test/TestTraceRetriever.js new file mode 100644 index 0000000000..ccc3d09ed9 --- /dev/null +++ b/test/TestTraceRetriever.js @@ -0,0 +1,38 @@ +'use strict' +var traceHelper = require('../src/helpers/traceHelper') +var traceInvokation = require('./resources/contractInvokationTrace') + +function TestTraceRetriever () { + this.storages = {} // contains all intial storage (by addresses) +} + +TestTraceRetriever.prototype.getTrace = function (txHash, callback) { + console.log(traceInvokation) + callback(null, traceInvokation) +} + +/* not used */ +TestTraceRetriever.prototype.getStorage = function (tx, address, callback) { + if (traceHelper.isContractCreation(address)) { + callback(null, {}) + } else if (this.storages[address]) { + callback(null, this.storages[address]) + } else { + /* + return storage + */ + /* + var self = this + this.web3.debug.storageAt(tx.blockNumber.toString(), tx.transactionIndex, address, function (error, result) { + self.storages[address] = result + callback(error, result) + }) + */ + } +} + +TestTraceRetriever.prototype.debugStorageAtAvailable = function () { + return false // storageAt not available if using geth +} + +module.exports = TestTraceRetriever diff --git a/test/codeManager.js b/test/codeManager.js new file mode 100644 index 0000000000..542ebcf730 --- /dev/null +++ b/test/codeManager.js @@ -0,0 +1,77 @@ +'use strict' +var tape = require('tape') +var init = require('../src/helpers/init') +var txInvokation = require('./resources/contractInvokationTx') +var TestTraceRetriever = require('./TestTraceRetriever') +var contractCode = require('./resources/contractInvokationCode') + +tape('CodeManager', function (t) { + var codeManager + var context = init.loadContext() + codeManager = context.codeManager + context.traceManager.traceRetriever = new TestTraceRetriever() + codeManager.codeResolver.cacheExecutingCode('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', contractCode) // so a call to web3 is not necessary + context.traceManager.resolveTrace(txInvokation, function (success) { + if (!success) { + t.fail(' - traceManager.resolveTrace - failed') + } else { + continueTesting(t, codeManager) + } + }) +}) + +function continueTesting (t, codeManager) { + t.test('CodeManager.init', function (st) { + st.end() + }) + + t.test('CodeManager.resolveStep', function (st) { + st.plan(6) + codeManager.register('indexChanged', this, function (index) { + if (index === undefined || index === null) { + st.fail(index) + } else { + st.ok(index === 6 || index === 0) + } + }) + + codeManager.register('codeChanged', this, function (code, address, index) { + console.log(address + ' ' + index + ' ' + code) + if (!code) { + st.fail('no codes') + } else { + st.ok(address === '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5' || address === '(Contract Creation - Step 63)') + if (address === '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5') { + console.log(address + ' ' + code[25]) + st.ok(code[25].indexOf('DUP') !== -1) + } else if (address === '(Contract Creation - Step 63)') { + console.log(address + ' ' + code[25]) + st.ok(code[25].indexOf('JUMPDEST') !== -1) + } + } + }) + codeManager.resolveStep(0, txInvokation) + codeManager.resolveStep(70, txInvokation) + }) + + t.test('CodeManager.getInstructionIndex', function (st) { + st.plan(2) + codeManager.getInstructionIndex('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', 16, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === 25) + } + }) + + codeManager.getInstructionIndex('(Contract Creation - Step 63)', 70, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === 6) + } + }) + }) +} diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000000..00b04e0274 --- /dev/null +++ b/test/index.js @@ -0,0 +1,11 @@ +'use strict' +var tape = require('tape') +var init = require('../src/helpers/init') +tape('index', function (t) { + t.test('loadContext - web3', function (st) { + var context = init.loadContext() + st.notEqual(context.web3, undefined) + st.notEqual(context.web3, null) + st.end() + }) +}) diff --git a/test/resources/contractInvokationCode.js b/test/resources/contractInvokationCode.js new file mode 100644 index 0000000000..6ad8e71169 --- /dev/null +++ b/test/resources/contractInvokationCode.js @@ -0,0 +1 @@ +module.exports = '0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806360fe47b11460415780636d4ce63c14605757603f565b005b605560048080359060200190919050506089565b005b606260048050506078565b6040518082815260200191505060405180910390f35b600060006000505490506086565b90565b80600060005081905550602d6040516045806100f083390180828152602001915050604051809103906000f0600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690830217905550602281016000600050819055505b505660606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055505b50600a80603b6000396000f360606040526008565b00' \ No newline at end of file diff --git a/test/resources/contractInvokationTrace.js b/test/resources/contractInvokationTrace.js new file mode 100644 index 0000000000..b10a9e4214 --- /dev/null +++ b/test/resources/contractInvokationTrace.js @@ -0,0 +1,2 @@ +module.exports = +{'gas':'0x0000000000000000000000000000000000000000000000000000000000019def','return':'0x','structLogs':[{'calldata':'0x60fe47b10000000000000000000000000000000000000000000000000000000000000038','gas':'84503','gasCost':'3','memory':[],'op':'PUSH1','pc':'0','stack':[],'steps':0,'storage':{'0x00':'0x2d'}},{'gas':'84500','gasCost':'3','op':'PUSH1','pc':'2','stack':['0x60'],'steps':1,'storage':{'0x00':'0x2d'}},{'gas':'84497','gasCost':'12','memexpand':'3','op':'MSTORE','pc':'4','stack':['0x60','0x40'],'steps':2,'storage':{'0x00':'0x2d'}},{'gas':'84485','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060'],'op':'PUSH1','pc':'5','stack':[],'steps':3,'storage':{'0x00':'0x2d'}},{'gas':'84482','gasCost':'3','op':'CALLDATALOAD','pc':'7','stack':['0x00'],'steps':4,'storage':{'0x00':'0x2d'}},{'gas':'84479','gasCost':'3','op':'PUSH29','pc':'8','stack':['0x60fe47b100000000000000000000000000000000000000000000000000000000'],'steps':5,'storage':{'0x00':'0x2d'}},{'gas':'84476','gasCost':'3','op':'SWAP1','pc':'38','stack':['0x60fe47b100000000000000000000000000000000000000000000000000000000','0x0100000000000000000000000000000000000000000000000000000000'],'steps':6,'storage':{'0x00':'0x2d'}},{'gas':'84473','gasCost':'5','op':'DIV','pc':'39','stack':['0x0100000000000000000000000000000000000000000000000000000000','0x60fe47b100000000000000000000000000000000000000000000000000000000'],'steps':7,'storage':{'0x00':'0x2d'}},{'gas':'84468','gasCost':'3','op':'DUP1','pc':'40','stack':['0x60fe47b1'],'steps':8,'storage':{'0x00':'0x2d'}},{'gas':'84465','gasCost':'3','op':'PUSH4','pc':'41','stack':['0x60fe47b1','0x60fe47b1'],'steps':9,'storage':{'0x00':'0x2d'}},{'gas':'84462','gasCost':'3','op':'EQ','pc':'46','stack':['0x60fe47b1','0x60fe47b1','0x60fe47b1'],'steps':10,'storage':{'0x00':'0x2d'}},{'gas':'84459','gasCost':'3','op':'PUSH1','pc':'47','stack':['0x60fe47b1','0x01'],'steps':11,'storage':{'0x00':'0x2d'}},{'gas':'84456','gasCost':'10','op':'JUMPI','pc':'49','stack':['0x60fe47b1','0x01','0x41'],'steps':12,'storage':{'0x00':'0x2d'}},{'gas':'84446','gasCost':'1','op':'JUMPDEST','pc':'65','stack':['0x60fe47b1'],'steps':13,'storage':{'0x00':'0x2d'}},{'gas':'84445','gasCost':'3','op':'PUSH1','pc':'66','stack':['0x60fe47b1'],'steps':14,'storage':{'0x00':'0x2d'}},{'gas':'84442','gasCost':'3','op':'PUSH1','pc':'68','stack':['0x60fe47b1','0x55'],'steps':15,'storage':{'0x00':'0x2d'}},{'gas':'84439','gasCost':'3','op':'DUP1','pc':'70','stack':['0x60fe47b1','0x55','0x04'],'steps':16,'storage':{'0x00':'0x2d'}},{'gas':'84436','gasCost':'3','op':'DUP1','pc':'71','stack':['0x60fe47b1','0x55','0x04','0x04'],'steps':17,'storage':{'0x00':'0x2d'}},{'gas':'84433','gasCost':'3','op':'CALLDATALOAD','pc':'72','stack':['0x60fe47b1','0x55','0x04','0x04','0x04'],'steps':18,'storage':{'0x00':'0x2d'}},{'gas':'84430','gasCost':'3','op':'SWAP1','pc':'73','stack':['0x60fe47b1','0x55','0x04','0x04','0x38'],'steps':19,'storage':{'0x00':'0x2d'}},{'gas':'84427','gasCost':'3','op':'PUSH1','pc':'74','stack':['0x60fe47b1','0x55','0x04','0x38','0x04'],'steps':20,'storage':{'0x00':'0x2d'}},{'gas':'84424','gasCost':'3','op':'ADD','pc':'76','stack':['0x60fe47b1','0x55','0x04','0x38','0x04','0x20'],'steps':21,'storage':{'0x00':'0x2d'}},{'gas':'84421','gasCost':'3','op':'SWAP1','pc':'77','stack':['0x60fe47b1','0x55','0x04','0x38','0x24'],'steps':22,'storage':{'0x00':'0x2d'}},{'gas':'84418','gasCost':'3','op':'SWAP2','pc':'78','stack':['0x60fe47b1','0x55','0x04','0x24','0x38'],'steps':23,'storage':{'0x00':'0x2d'}},{'gas':'84415','gasCost':'3','op':'SWAP1','pc':'79','stack':['0x60fe47b1','0x55','0x38','0x24','0x04'],'steps':24,'storage':{'0x00':'0x2d'}},{'gas':'84412','gasCost':'2','op':'POP','pc':'80','stack':['0x60fe47b1','0x55','0x38','0x04','0x24'],'steps':25,'storage':{'0x00':'0x2d'}},{'gas':'84410','gasCost':'2','op':'POP','pc':'81','stack':['0x60fe47b1','0x55','0x38','0x04'],'steps':26,'storage':{'0x00':'0x2d'}},{'gas':'84408','gasCost':'3','op':'PUSH1','pc':'82','stack':['0x60fe47b1','0x55','0x38'],'steps':27,'storage':{'0x00':'0x2d'}},{'gas':'84405','gasCost':'8','op':'JUMP','pc':'84','stack':['0x60fe47b1','0x55','0x38','0x89'],'steps':28,'storage':{'0x00':'0x2d'}},{'gas':'84397','gasCost':'1','op':'JUMPDEST','pc':'137','stack':['0x60fe47b1','0x55','0x38'],'steps':29,'storage':{'0x00':'0x2d'}},{'gas':'84396','gasCost':'3','op':'DUP1','pc':'138','stack':['0x60fe47b1','0x55','0x38'],'steps':30,'storage':{'0x00':'0x2d'}},{'gas':'84393','gasCost':'3','op':'PUSH1','pc':'139','stack':['0x60fe47b1','0x55','0x38','0x38'],'steps':31,'storage':{'0x00':'0x2d'}},{'gas':'84390','gasCost':'3','op':'PUSH1','pc':'141','stack':['0x60fe47b1','0x55','0x38','0x38','0x00'],'steps':32,'storage':{'0x00':'0x2d'}},{'gas':'84387','gasCost':'2','op':'POP','pc':'143','stack':['0x60fe47b1','0x55','0x38','0x38','0x00','0x00'],'steps':33,'storage':{'0x00':'0x2d'}},{'gas':'84385','gasCost':'3','op':'DUP2','pc':'144','stack':['0x60fe47b1','0x55','0x38','0x38','0x00'],'steps':34,'storage':{'0x00':'0x2d'}},{'gas':'84382','gasCost':'3','op':'SWAP1','pc':'145','stack':['0x60fe47b1','0x55','0x38','0x38','0x00','0x38'],'steps':35,'storage':{'0x00':'0x2d'}},{'gas':'84379','gasCost':'5000','op':'SSTORE','pc':'146','stack':['0x60fe47b1','0x55','0x38','0x38','0x38','0x00'],'steps':36,'storage':{'0x00':'0x2d'}},{'gas':'79379','gasCost':'2','op':'POP','pc':'147','stack':['0x60fe47b1','0x55','0x38','0x38'],'steps':37,'storage':{'0x00':'0x38'}},{'gas':'79377','gasCost':'3','op':'PUSH1','pc':'148','stack':['0x60fe47b1','0x55','0x38'],'steps':38,'storage':{'0x00':'0x38'}},{'gas':'79374','gasCost':'3','op':'PUSH1','pc':'150','stack':['0x60fe47b1','0x55','0x38','0x2d'],'steps':39,'storage':{'0x00':'0x38'}},{'gas':'79371','gasCost':'3','op':'MLOAD','pc':'152','stack':['0x60fe47b1','0x55','0x38','0x2d','0x40'],'steps':40,'storage':{'0x00':'0x38'}},{'gas':'79368','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060'],'op':'PUSH1','pc':'153','stack':['0x60fe47b1','0x55','0x38','0x2d','0x60'],'steps':41,'storage':{'0x00':'0x38'}},{'gas':'79365','gasCost':'3','op':'DUP1','pc':'155','stack':['0x60fe47b1','0x55','0x38','0x2d','0x60','0x45'],'steps':42,'storage':{'0x00':'0x38'}},{'gas':'79362','gasCost':'3','op':'PUSH2','pc':'156','stack':['0x60fe47b1','0x55','0x38','0x2d','0x60','0x45','0x45'],'steps':43,'storage':{'0x00':'0x38'}},{'gas':'79359','gasCost':'3','op':'DUP4','pc':'159','stack':['0x60fe47b1','0x55','0x38','0x2d','0x60','0x45','0x45','0xf0'],'steps':44,'storage':{'0x00':'0x38'}},{'gas':'79356','gasCost':'21','memexpand':'3','op':'CODECOPY','pc':'160','stack':['0x60fe47b1','0x55','0x38','0x2d','0x60','0x45','0x45','0xf0','0x60'],'steps':45,'storage':{'0x00':'0x38'}},{'gas':'79335','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060','6060604052604051602080604583398101604052808051906020019091905050','5b806001016000600050819055505b50600a80603b6000396000f36060604052','6008565b00000000000000000000000000000000000000000000000000000000'],'op':'ADD','pc':'161','stack':['0x60fe47b1','0x55','0x38','0x2d','0x60','0x45'],'steps':46,'storage':{'0x00':'0x38'}},{'gas':'79332','gasCost':'3','op':'DUP1','pc':'162','stack':['0x60fe47b1','0x55','0x38','0x2d','0xa5'],'steps':47,'storage':{'0x00':'0x38'}},{'gas':'79329','gasCost':'3','op':'DUP3','pc':'163','stack':['0x60fe47b1','0x55','0x38','0x2d','0xa5','0xa5'],'steps':48,'storage':{'0x00':'0x38'}},{'gas':'79326','gasCost':'3','op':'DUP2','pc':'164','stack':['0x60fe47b1','0x55','0x38','0x2d','0xa5','0xa5','0x2d'],'steps':49,'storage':{'0x00':'0x38'}},{'gas':'79323','gasCost':'6','memexpand':'1','op':'MSTORE','pc':'165','stack':['0x60fe47b1','0x55','0x38','0x2d','0xa5','0xa5','0x2d','0xa5'],'steps':50,'storage':{'0x00':'0x38'}},{'gas':'79317','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060','6060604052604051602080604583398101604052808051906020019091905050','5b806001016000600050819055505b50600a80603b6000396000f36060604052','6008565b00000000000000000000000000000000000000000000000000000000','000000002d000000000000000000000000000000000000000000000000000000'],'op':'PUSH1','pc':'166','stack':['0x60fe47b1','0x55','0x38','0x2d','0xa5','0xa5'],'steps':51,'storage':{'0x00':'0x38'}},{'gas':'79314','gasCost':'3','op':'ADD','pc':'168','stack':['0x60fe47b1','0x55','0x38','0x2d','0xa5','0xa5','0x20'],'steps':52,'storage':{'0x00':'0x38'}},{'gas':'79311','gasCost':'3','op':'SWAP2','pc':'169','stack':['0x60fe47b1','0x55','0x38','0x2d','0xa5','0xc5'],'steps':53,'storage':{'0x00':'0x38'}},{'gas':'79308','gasCost':'2','op':'POP','pc':'170','stack':['0x60fe47b1','0x55','0x38','0xc5','0xa5','0x2d'],'steps':54,'storage':{'0x00':'0x38'}},{'gas':'79306','gasCost':'2','op':'POP','pc':'171','stack':['0x60fe47b1','0x55','0x38','0xc5','0xa5'],'steps':55,'storage':{'0x00':'0x38'}},{'gas':'79304','gasCost':'3','op':'PUSH1','pc':'172','stack':['0x60fe47b1','0x55','0x38','0xc5'],'steps':56,'storage':{'0x00':'0x38'}},{'gas':'79301','gasCost':'3','op':'MLOAD','pc':'174','stack':['0x60fe47b1','0x55','0x38','0xc5','0x40'],'steps':57,'storage':{'0x00':'0x38'}},{'gas':'79298','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060','6060604052604051602080604583398101604052808051906020019091905050','5b806001016000600050819055505b50600a80603b6000396000f36060604052','6008565b00000000000000000000000000000000000000000000000000000000','000000002d000000000000000000000000000000000000000000000000000000'],'op':'DUP1','pc':'175','stack':['0x60fe47b1','0x55','0x38','0xc5','0x60'],'steps':58,'storage':{'0x00':'0x38'}},{'gas':'79295','gasCost':'3','op':'SWAP2','pc':'176','stack':['0x60fe47b1','0x55','0x38','0xc5','0x60','0x60'],'steps':59,'storage':{'0x00':'0x38'}},{'gas':'79292','gasCost':'3','op':'SUB','pc':'177','stack':['0x60fe47b1','0x55','0x38','0x60','0x60','0xc5'],'steps':60,'storage':{'0x00':'0x38'}},{'gas':'79289','gasCost':'3','op':'SWAP1','pc':'178','stack':['0x60fe47b1','0x55','0x38','0x60','0x65'],'steps':61,'storage':{'0x00':'0x38'}},{'gas':'79286','gasCost':'3','op':'PUSH1','pc':'179','stack':['0x60fe47b1','0x55','0x38','0x65','0x60'],'steps':62,'storage':{'0x00':'0x38'}},{'gas':'79283','gasCost':'32000','op':'CREATE','pc':'181','stack':['0x60fe47b1','0x55','0x38','0x65','0x60','0x00'],'steps':63,'storage':{'0x00':'0x38'}},{'calldata':'0x','gas':'47283','gasCost':'3','memory':[],'op':'PUSH1','pc':'0','stack':[],'steps':0,'storage':{}},{'gas':'47280','gasCost':'3','op':'PUSH1','pc':'2','stack':['0x60'],'steps':1,'storage':{}},{'gas':'47277','gasCost':'12','memexpand':'3','op':'MSTORE','pc':'4','stack':['0x60','0x40'],'steps':2,'storage':{}},{'gas':'47265','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060'],'op':'PUSH1','pc':'5','stack':[],'steps':3,'storage':{}},{'gas':'47262','gasCost':'3','op':'MLOAD','pc':'7','stack':['0x40'],'steps':4,'storage':{}},{'gas':'47259','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060'],'op':'PUSH1','pc':'8','stack':['0x60'],'steps':5,'storage':{}},{'gas':'47256','gasCost':'3','op':'DUP1','pc':'10','stack':['0x60','0x20'],'steps':6,'storage':{}},{'gas':'47253','gasCost':'3','op':'PUSH1','pc':'11','stack':['0x60','0x20','0x20'],'steps':7,'storage':{}},{'gas':'47250','gasCost':'3','op':'DUP4','pc':'13','stack':['0x60','0x20','0x20','0x45'],'steps':8,'storage':{}},{'gas':'47247','gasCost':'9','memexpand':'1','op':'CODECOPY','pc':'14','stack':['0x60','0x20','0x20','0x45','0x60'],'steps':9,'storage':{}},{'gas':'47238','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060','000000000000000000000000000000000000000000000000000000000000002d'],'op':'DUP2','pc':'15','stack':['0x60','0x20'],'steps':10,'storage':{}},{'gas':'47235','gasCost':'3','op':'ADD','pc':'16','stack':['0x60','0x20','0x60'],'steps':11,'storage':{}},{'gas':'47232','gasCost':'3','op':'PUSH1','pc':'17','stack':['0x60','0x80'],'steps':12,'storage':{}},{'gas':'47229','gasCost':'3','op':'MSTORE','pc':'19','stack':['0x60','0x80','0x40'],'steps':13,'storage':{}},{'gas':'47226','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000080','000000000000000000000000000000000000000000000000000000000000002d'],'op':'DUP1','pc':'20','stack':['0x60'],'steps':14,'storage':{}},{'gas':'47223','gasCost':'3','op':'DUP1','pc':'21','stack':['0x60','0x60'],'steps':15,'storage':{}},{'gas':'47220','gasCost':'3','op':'MLOAD','pc':'22','stack':['0x60','0x60','0x60'],'steps':16,'storage':{}},{'gas':'47217','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000080','000000000000000000000000000000000000000000000000000000000000002d'],'op':'SWAP1','pc':'23','stack':['0x60','0x60','0x2d'],'steps':17,'storage':{}},{'gas':'47214','gasCost':'3','op':'PUSH1','pc':'24','stack':['0x60','0x2d','0x60'],'steps':18,'storage':{}},{'gas':'47211','gasCost':'3','op':'ADD','pc':'26','stack':['0x60','0x2d','0x60','0x20'],'steps':19,'storage':{}},{'gas':'47208','gasCost':'3','op':'SWAP1','pc':'27','stack':['0x60','0x2d','0x80'],'steps':20,'storage':{}},{'gas':'47205','gasCost':'3','op':'SWAP2','pc':'28','stack':['0x60','0x80','0x2d'],'steps':21,'storage':{}},{'gas':'47202','gasCost':'3','op':'SWAP1','pc':'29','stack':['0x2d','0x80','0x60'],'steps':22,'storage':{}},{'gas':'47199','gasCost':'2','op':'POP','pc':'30','stack':['0x2d','0x60','0x80'],'steps':23,'storage':{}},{'gas':'47197','gasCost':'2','op':'POP','pc':'31','stack':['0x2d','0x60'],'steps':24,'storage':{}},{'gas':'47195','gasCost':'1','op':'JUMPDEST','pc':'32','stack':['0x2d'],'steps':25,'storage':{}},{'gas':'47194','gasCost':'3','op':'DUP1','pc':'33','stack':['0x2d'],'steps':26,'storage':{}},{'gas':'47191','gasCost':'3','op':'PUSH1','pc':'34','stack':['0x2d','0x2d'],'steps':27,'storage':{}},{'gas':'47188','gasCost':'3','op':'ADD','pc':'36','stack':['0x2d','0x2d','0x01'],'steps':28,'storage':{}},{'gas':'47185','gasCost':'3','op':'PUSH1','pc':'37','stack':['0x2d','0x2e'],'steps':29,'storage':{}},{'gas':'47182','gasCost':'3','op':'PUSH1','pc':'39','stack':['0x2d','0x2e','0x00'],'steps':30,'storage':{}},{'gas':'47179','gasCost':'2','op':'POP','pc':'41','stack':['0x2d','0x2e','0x00','0x00'],'steps':31,'storage':{}},{'gas':'47177','gasCost':'3','op':'DUP2','pc':'42','stack':['0x2d','0x2e','0x00'],'steps':32,'storage':{}},{'gas':'47174','gasCost':'3','op':'SWAP1','pc':'43','stack':['0x2d','0x2e','0x00','0x2e'],'steps':33,'storage':{}},{'gas':'47171','gasCost':'20000','op':'SSTORE','pc':'44','stack':['0x2d','0x2e','0x2e','0x00'],'steps':34,'storage':{}},{'gas':'27171','gasCost':'2','op':'POP','pc':'45','stack':['0x2d','0x2e'],'steps':35,'storage':{'0x00':'0x2e'}},{'gas':'27169','gasCost':'1','op':'JUMPDEST','pc':'46','stack':['0x2d'],'steps':36,'storage':{'0x00':'0x2e'}},{'gas':'27168','gasCost':'2','op':'POP','pc':'47','stack':['0x2d'],'steps':37,'storage':{'0x00':'0x2e'}},{'gas':'27166','gasCost':'3','op':'PUSH1','pc':'48','stack':[],'steps':38,'storage':{'0x00':'0x2e'}},{'gas':'27163','gasCost':'3','op':'DUP1','pc':'50','stack':['0x0a'],'steps':39,'storage':{'0x00':'0x2e'}},{'gas':'27160','gasCost':'3','op':'PUSH1','pc':'51','stack':['0x0a','0x0a'],'steps':40,'storage':{'0x00':'0x2e'}},{'gas':'27157','gasCost':'3','op':'PUSH1','pc':'53','stack':['0x0a','0x0a','0x3b'],'steps':41,'storage':{'0x00':'0x2e'}},{'gas':'27154','gasCost':'6','op':'CODECOPY','pc':'55','stack':['0x0a','0x0a','0x3b','0x00'],'steps':42,'storage':{'0x00':'0x2e'}},{'gas':'27148','gasCost':'3','memory':['60606040526008565b0000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000080','000000000000000000000000000000000000000000000000000000000000002d'],'op':'PUSH1','pc':'56','stack':['0x0a'],'steps':43,'storage':{'0x00':'0x2e'}},{'gas':'27145','gasCost':'0','op':'RETURN','pc':'58','stack':['0x0a','0x00'],'steps':44,'storage':{'0x00':'0x2e'}},{'calldata':'0x60fe47b10000000000000000000000000000000000000000000000000000000000000038','gas':'25145','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060','6060604052604051602080604583398101604052808051906020019091905050','5b806001016000600050819055505b50600a80603b6000396000f36060604052','6008565b00000000000000000000000000000000000000000000000000000000','000000002d000000000000000000000000000000000000000000000000000000'],'op':'PUSH1','pc':'182','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'],'steps':64,'storage':{'0x00':'0x38'}},{'gas':'25142','gasCost':'3','memory':['0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000000','0000000000000000000000000000000000000000000000000000000000000060','6060604052604051602080604583398101604052808051906020019091905050','5b806001016000600050819055505b50600a80603b6000396000f36060604052','6008565b00000000000000000000000000000000000000000000000000000000','000000002d000000000000000000000000000000000000000000000000000000'],'op':'PUSH1','pc':'184','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01'],'steps':65,'storage':{'0x00':'0x38'}},{'gas':'25139','gasCost':'3','op':'PUSH2','pc':'186','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x00'],'steps':66,'storage':{'0x00':'0x38'}},{'gas':'25136','gasCost':'10','op':'EXP','pc':'189','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x00','0x0100'],'steps':67,'storage':{'0x00':'0x38'}},{'gas':'25126','gasCost':'3','op':'DUP2','pc':'190','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01'],'steps':68,'storage':{'0x00':'0x38'}},{'gas':'25123','gasCost':'50','op':'SLOAD','pc':'191','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01','0x01'],'steps':69,'storage':{'0x00':'0x38'}},{'gas':'25073','gasCost':'3','op':'DUP2','pc':'192','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01','0x00'],'steps':70,'storage':{'0x00':'0x38'}},{'gas':'25070','gasCost':'3','op':'PUSH20','pc':'193','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01','0x00','0x01'],'steps':71,'storage':{'0x00':'0x38'}},{'gas':'25067','gasCost':'5','op':'MUL','pc':'214','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01','0x00','0x01','0xffffffffffffffffffffffffffffffffffffffff'],'steps':72,'storage':{'0x00':'0x38'}},{'gas':'25062','gasCost':'3','op':'NOT','pc':'215','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01','0x00','0xffffffffffffffffffffffffffffffffffffffff'],'steps':73,'storage':{'0x00':'0x38'}},{'gas':'25059','gasCost':'3','op':'AND','pc':'216','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01','0x00','0xffffffffffffffffffffffff0000000000000000000000000000000000000000'],'steps':74,'storage':{'0x00':'0x38'}},{'gas':'25056','gasCost':'3','op':'SWAP1','pc':'217','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x01','0x00'],'steps':75,'storage':{'0x00':'0x38'}},{'gas':'25053','gasCost':'3','op':'DUP4','pc':'218','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x00','0x01'],'steps':76,'storage':{'0x00':'0x38'}},{'gas':'25050','gasCost':'5','op':'MUL','pc':'219','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x00','0x01','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'],'steps':77,'storage':{'0x00':'0x38'}},{'gas':'25045','gasCost':'3','op':'OR','pc':'220','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0x00','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'],'steps':78,'storage':{'0x00':'0x38'}},{'gas':'25042','gasCost':'3','op':'SWAP1','pc':'221','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'],'steps':79,'storage':{'0x00':'0x38'}},{'gas':'25039','gasCost':'20000','op':'SSTORE','pc':'222','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95','0x01'],'steps':80,'storage':{'0x00':'0x38'}},{'gas':'5039','gasCost':'2','op':'POP','pc':'223','stack':['0x60fe47b1','0x55','0x38','0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'],'steps':81,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5037','gasCost':'3','op':'PUSH1','pc':'224','stack':['0x60fe47b1','0x55','0x38'],'steps':82,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5034','gasCost':'3','op':'DUP2','pc':'226','stack':['0x60fe47b1','0x55','0x38','0x22'],'steps':83,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5031','gasCost':'3','op':'ADD','pc':'227','stack':['0x60fe47b1','0x55','0x38','0x22','0x38'],'steps':84,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5028','gasCost':'3','op':'PUSH1','pc':'228','stack':['0x60fe47b1','0x55','0x38','0x5a'],'steps':85,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5025','gasCost':'3','op':'PUSH1','pc':'230','stack':['0x60fe47b1','0x55','0x38','0x5a','0x00'],'steps':86,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5022','gasCost':'2','op':'POP','pc':'232','stack':['0x60fe47b1','0x55','0x38','0x5a','0x00','0x00'],'steps':87,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5020','gasCost':'3','op':'DUP2','pc':'233','stack':['0x60fe47b1','0x55','0x38','0x5a','0x00'],'steps':88,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5017','gasCost':'3','op':'SWAP1','pc':'234','stack':['0x60fe47b1','0x55','0x38','0x5a','0x00','0x5a'],'steps':89,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'5014','gasCost':'5000','op':'SSTORE','pc':'235','stack':['0x60fe47b1','0x55','0x38','0x5a','0x5a','0x00'],'steps':90,'storage':{'0x00':'0x38','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'14','gasCost':'2','op':'POP','pc':'236','stack':['0x60fe47b1','0x55','0x38','0x5a'],'steps':91,'storage':{'0x00':'0x5a','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'12','gasCost':'1','op':'JUMPDEST','pc':'237','stack':['0x60fe47b1','0x55','0x38'],'steps':92,'storage':{'0x00':'0x5a','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'11','gasCost':'2','op':'POP','pc':'238','stack':['0x60fe47b1','0x55','0x38'],'steps':93,'storage':{'0x00':'0x5a','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'9','gasCost':'8','op':'JUMP','pc':'239','stack':['0x60fe47b1','0x55'],'steps':94,'storage':{'0x00':'0x5a','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'1','gasCost':'1','op':'JUMPDEST','pc':'85','stack':['0x60fe47b1'],'steps':95,'storage':{'0x00':'0x5a','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}},{'gas':'0','gasCost':'0','op':'STOP','pc':'86','stack':['0x60fe47b1'],'steps':96,'storage':{'0x00':'0x5a','0x01':'0xd01f65e3472f24faf45f08f8698ec4da1bf32a95'}}]} \ No newline at end of file diff --git a/test/resources/contractInvokationTx.js b/test/resources/contractInvokationTx.js new file mode 100644 index 0000000000..c0eddd11a5 --- /dev/null +++ b/test/resources/contractInvokationTx.js @@ -0,0 +1,2 @@ +module.exports = +{'blockHash':'0xd1d34932f8733e0485b7d9bf8500c4046d650f20ed7792508c304304fa7bbfac','blockNumber':89,'from':'0x00101c5bfa3fc8bad02c9f5fd65b069306251915','gas':105967,'gasPrice':'20000000000','hash':'0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51','input':'0x60fe47b10000000000000000000000000000000000000000000000000000000000000038','nonce':3,'to':'0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5','transactionIndex':0,'value':'0'} \ No newline at end of file diff --git a/test/tests.js b/test/tests.js new file mode 100644 index 0000000000..96ea8c66d4 --- /dev/null +++ b/test/tests.js @@ -0,0 +1,4 @@ +'use strict' +require('./index.js') +require('./traceManager.js') +require('./codeManager.js') diff --git a/test/traceManager.js b/test/traceManager.js new file mode 100644 index 0000000000..89fe262ca5 --- /dev/null +++ b/test/traceManager.js @@ -0,0 +1,298 @@ +'use strict' +var TraceManager = require('../src/trace/traceManager') +var tape = require('tape') +var init = require('../src/helpers/init') +var TestTraceRetriever = require('./TestTraceRetriever') +var txInvokation = require('./resources/contractInvokationTx') + +tape('TraceManager', function (t) { + var traceManager + + t.test('TraceManager.init', function (st) { + var context = init.loadContext() + traceManager = new TraceManager(context.web3) + traceManager.traceRetriever = new TestTraceRetriever() + st.end() + }) + + t.test('TraceManager.resolveTrace', function (st) { + traceManager.resolveTrace(txInvokation, function (success) { + if (!success) { + st.fail(' - traceManager.resolveTrace - failed') + } else { + st.end() + } + }) + }) + + t.test('TraceManager.getLength ', function (st) { + traceManager.getLength(function (error, result) { + if (error) { + st.fail(error) + } else { + st.end() + } + }) + }) + + t.test('TraceManager.inRange ', function (st) { + st.notOk(traceManager.inRange(-1)) + st.ok(traceManager.inRange(10)) + st.notOk(traceManager.inRange(142)) + st.ok(traceManager.inRange(141)) + st.end() + }) + + t.test('TraceManager.getStorageAt', function (st) { + traceManager.getStorageAt(0, txInvokation, function (error, result) { + if (error) { + st.fail(error) + } else { + st.ok(result['0x00'] === '0x2d') + st.end() + } + }) + }) + + t.test('TraceManager.getCallData', function (st) { + traceManager.getCallDataAt(0, function (error, result) { + if (error) { + st.fail(error) + } else { + st.ok(result[0] === '0x60fe47b10000000000000000000000000000000000000000000000000000000000000038') + st.end() + } + }) + }) + + t.test('TraceManager.getCallStackAt', function (st) { + st.plan(3) + traceManager.getCallStackAt(0, function (error, result) { + if (error) { + st.fail(error) + } else { + st.ok(result[0] === '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5') + } + }) + + traceManager.getCallStackAt(64, function (error, result) { + if (error) { + st.fail(error) + } else { + st.ok(result.length === 2) + st.ok(result[1] === '(Contract Creation - Step 63)') + } + }) + }) + + t.test('TraceManager.getStackAt', function (st) { + st.plan(3) + traceManager.getStackAt(0, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result.length === 0) + } + }) + + traceManager.getStackAt(28, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result.length === 4) + st.ok(result[3] === '0x60fe47b1') + } + }) + }) + + t.test('TraceManager.getLastCallChangeSince', function (st) { + st.plan(3) + traceManager.getLastCallChangeSince(10, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === 0) + } + }) + + traceManager.getLastCallChangeSince(70, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === 64) + } + }) + + traceManager.getLastCallChangeSince(111, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === 109) + } + }) + }) + + t.test('TraceManager.getCurrentCalledAddressAt', function (st) { + st.plan(3) + traceManager.getCurrentCalledAddressAt(10, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5') + } + }) + + traceManager.getCurrentCalledAddressAt(70, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '(Contract Creation - Step 63)') + } + }) + + traceManager.getCurrentCalledAddressAt(111, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5') + } + }) + }) + + t.test('TraceManager.getContractCreationCode', function (st) { // contract code has been retrieved from the memory + traceManager.getContractCreationCode('(Contract Creation - Step 63)', function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '0x60606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055505b50600a80603b6000396000f360606040526008565b00000000000000000000000000000000000000000000000000000000000000002d') + st.end() + } + }) + }) + + t.test('TraceManager.getMemoryAt', function (st) { + st.plan(3) + traceManager.getMemoryAt(0, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result.length === 0) + } + }) + + traceManager.getMemoryAt(34, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result.length === 3) + st.ok(result[2] === '0000000000000000000000000000000000000000000000000000000000000060') + } + }) + }) + + t.test('TraceManager.getCurrentPC', function (st) { + traceManager.getCurrentPC(13, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '65') + st.end() + } + }) + }) + + t.test('TraceManager.getCurrentStep', function (st) { + traceManager.getCurrentStep(66, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === 2) + st.end() + } + }) + }) + + t.test('TraceManager.getMemExpand', function (st) { + traceManager.getMemExpand(2, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '3') + st.end() + } + }) + }) + + t.test('TraceManager.getStepCost', function (st) { + traceManager.getStepCost(34, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '3') + st.end() + } + }) + }) + + t.test('TraceManager.getRemainingGas', function (st) { + traceManager.getRemainingGas(55, function (error, result) { + console.log(result) + if (error) { + st.fail(error) + } else { + st.ok(result === '79306') + st.end() + } + }) + }) + + t.test('TraceManager.findStepOverBack', function (st) { + var result = traceManager.findStepOverBack(116) + console.log(result) + st.ok(result === -1) + st.end() + }) + + t.test('TraceManager.findStepOverForward', function (st) { + var result = traceManager.findStepOverForward(66) + console.log(result) + st.ok(result === 108) + st.end() + }) + + t.test('TraceManager.findStepOutBack', function (st) { + var result = traceManager.findStepOutBack(70) + console.log(result) + st.ok(result === 63) + st.end() + }) + + t.test('TraceManager.findStepOutForward', function (st) { + var result = traceManager.findStepOutForward(15) + console.log(result) + st.ok(result === 142) + st.end() + }) + + t.test('TraceManager.findNextCall', function (st) { + var result = traceManager.findNextCall(10) + console.log(result) + st.ok(result === 63) + st.end() + }) +}) |