-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
322 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
libs/remix-debug/test/decoder/contracts/revert-state-sub-call.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
module.exports = { | ||
contract: ` | ||
pragma solidity ^0.8; | ||
contract MyContract { | ||
OtherContract myCall; | ||
constructor () { | ||
myCall = new OtherContract(); | ||
} | ||
function callOther() public { | ||
// Call 'doSomething' in the other contract | ||
bool result; | ||
(result, ) = address(myCall).call(abi.encodeWithSignature("doSomething()")); | ||
result; | ||
(result, ) = address(myCall).call(abi.encodeWithSignature("doSomething()")); | ||
} | ||
function callOther2() public { | ||
// Call 'doSomething' in the other contract | ||
myCall.doSomething(); | ||
myCall.doSomething(); | ||
} | ||
} | ||
// Assuming 'doSomething' in the other contract's code reverts due to some error... | ||
contract OtherContract { | ||
uint p; | ||
function doSomething() public returns(bool) { | ||
p = 234; | ||
revert("revert"); | ||
} | ||
function v() public returns (uint) { return p;} | ||
} | ||
` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module.exports = { | ||
contract: ` | ||
contract MyContract { | ||
uint public data; | ||
function foo(uint _data) external { | ||
bar(_data); | ||
baz(); | ||
} | ||
function bar(uint _data) internal { | ||
data = _data; | ||
} | ||
function baz() internal { | ||
revert("oops...."); | ||
} | ||
} | ||
` | ||
} |
138 changes: 138 additions & 0 deletions
138
libs/remix-debug/test/decoder/stateTests/revert-state-sub-call.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { CompilerAbstract } from '@remix-project/remix-solidity' | ||
import { EventManager } from '../../../src/eventManager' | ||
import { compilerInput } from '../../helpers/compilerHelper' | ||
import { TraceManager } from '../../../src/trace/traceManager' | ||
import { CodeManager } from '../../../src/code/codeManager' | ||
import { compile } from 'solc' | ||
import * as stateDecoder from '../../../src/solidity-decoder/stateDecoder' | ||
import { SolidityProxy } from '../../../src/solidity-decoder/solidityProxy' | ||
import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree' | ||
import * as vmCall from '../../vmCall' | ||
import { StorageResolver } from '../../../src/storage/storageResolver' | ||
import { StorageViewer } from '../../../src/storage/storageViewer' | ||
import { Address, bytesToHex } from '@ethereumjs/util' | ||
|
||
module.exports = async function testMappingStorage (st, cb) { | ||
const revertStateContract = require('../contracts/revert-state-sub-call.ts') | ||
const privateKey = Buffer.from('503f38a9c967ed597e47fe25643985f032b072db8075426a92110f82df48dfcb', 'hex') | ||
let output = compile(compilerInput(revertStateContract.contract)) | ||
output = JSON.parse(output); | ||
const sources = { | ||
target: 'test.sol', | ||
sources: { 'test.sol': { content: revertStateContract.contract } } | ||
} | ||
const compilationResults = new CompilerAbstract('json', output, sources) | ||
const web3 = await (vmCall as any).getWeb3(); | ||
(vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, undefined, 0, output.contracts['test.sol']['MyContract'].evm.bytecode.object, function (error, hash) { | ||
if (error) { | ||
console.log(error) | ||
st.end(error) | ||
} else { | ||
web3.eth.getTransactionReceipt(hash) | ||
.then(tx => { | ||
// const storage = await this.vm.stateManager.dumpStorage(data.to) | ||
// web3.eth.getCode(tx.contractAddress).then((code) => console.log('code:---', code)) | ||
// (vmCall as any).web3().debug.traceTransaction(hash).then((code) => console.log('trace:', code)) | ||
testRevertStateSubCall(st, privateKey, tx.contractAddress, output, compilationResults, web3, cb) | ||
} | ||
// st.end() | ||
) | ||
.catch(error => { | ||
st.end(error) | ||
}) | ||
} | ||
}) | ||
} | ||
|
||
function testRevertStateSubCall (st, privateKey, contractAddress, output, compilationResults, web3, cb) { | ||
// call to foo(22) | ||
(vmCall as any).sendTx(web3, { nonce: 1, privateKey: privateKey }, contractAddress, 0, '8e0bf849', | ||
function (error, hash) { | ||
if (error) { | ||
console.log(error) | ||
st.end(error) | ||
} else { | ||
web3.eth.getTransaction(hash) | ||
.then(tx => { | ||
const traceManager = new TraceManager({ web3 }) | ||
const codeManager = new CodeManager(traceManager) | ||
codeManager.clear() | ||
const solidityProxy = new SolidityProxy({ | ||
getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), | ||
getCode: codeManager.getCode.bind(codeManager), | ||
compilationResult: () => compilationResults | ||
}) | ||
const debuggerEvent = new EventManager() | ||
const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }) | ||
callTree.event.register('callTreeBuildFailed', (error) => { | ||
st.fail(error) | ||
}) | ||
callTree.event.register('callTreeNotReady', (reason) => { | ||
st.fail(reason) | ||
}) | ||
callTree.event.register('callTreeReady', (scopes, scopeStarts) => { | ||
const storageViewerMyContract = new StorageViewer({ | ||
stepIndex: 29, | ||
tx: tx, | ||
address: contractAddress | ||
}, new StorageResolver({ web3 }), traceManager) | ||
|
||
const stateVarsMyContract = stateDecoder.extractStateVariables('MyContract', output.sources) | ||
stateDecoder.decodeState(stateVarsMyContract, storageViewerMyContract).then((result) => { | ||
const contractAddressOtherContract = result['myCall'].value | ||
const storageViewerOtherContract1 = new StorageViewer({ | ||
stepIndex: 300, | ||
tx: tx, | ||
address: contractAddressOtherContract | ||
}, new StorageResolver({ web3 }), traceManager) | ||
|
||
const storageViewerOtherContract2 = new StorageViewer({ | ||
stepIndex: 550, | ||
tx: tx, | ||
address: contractAddressOtherContract | ||
}, new StorageResolver({ web3 }), traceManager) | ||
|
||
const storageViewerOtherContract3 = new StorageViewer({ | ||
stepIndex: 556, | ||
tx: tx, | ||
address: contractAddressOtherContract | ||
}, new StorageResolver({ web3 }), traceManager) | ||
|
||
const stateVars = stateDecoder.extractStateVariables('OtherContract', output.sources) | ||
stateDecoder.decodeState(stateVars, storageViewerOtherContract1).then((result) => { | ||
// value should be set | ||
st.equal(result['p'].value, '234') | ||
stateDecoder.decodeState(stateVars, storageViewerOtherContract2).then((result) => { | ||
// in the other sub call, the value is reverted | ||
st.equal(result['p'].value, '0') | ||
stateDecoder.decodeState(stateVars, storageViewerOtherContract3).then((result) => { | ||
// and reset back to 234 | ||
st.equal(result['p'].value, '234') | ||
cb() | ||
}, (reason) => { | ||
console.log('fail') | ||
st.end(reason) | ||
}) | ||
}) | ||
}, (reason) => { | ||
console.log('fail') | ||
st.end(reason) | ||
}) | ||
}) | ||
}, (reason) => { | ||
console.log('fail') | ||
st.end(reason) | ||
}) | ||
traceManager.resolveTrace(tx).then(() => { | ||
debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) | ||
}).catch((error) => { | ||
st.fail(error) | ||
}) | ||
}) | ||
.catch(error => { | ||
console.log(error) | ||
st.end(error) | ||
}) | ||
} | ||
}) | ||
} |
103 changes: 103 additions & 0 deletions
103
libs/remix-debug/test/decoder/stateTests/revert-state.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { CompilerAbstract } from '@remix-project/remix-solidity' | ||
import { EventManager } from '../../../src/eventManager' | ||
import { compilerInput } from '../../helpers/compilerHelper' | ||
import { TraceManager } from '../../../src/trace/traceManager' | ||
import { CodeManager } from '../../../src/code/codeManager' | ||
import { compile } from 'solc' | ||
import * as stateDecoder from '../../../src/solidity-decoder/stateDecoder' | ||
import { SolidityProxy } from '../../../src/solidity-decoder/solidityProxy' | ||
import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree' | ||
import * as vmCall from '../../vmCall' | ||
import { StorageResolver } from '../../../src/storage/storageResolver' | ||
import { StorageViewer } from '../../../src/storage/storageViewer' | ||
import { Address, bytesToHex } from '@ethereumjs/util' | ||
|
||
module.exports = async function testMappingStorage (st, cb) { | ||
const revertStateContract = require('../contracts/revert-state.ts') | ||
const privateKey = Buffer.from('503f38a9c967ed597e47fe25643985f032b072db8075426a92110f82df48dfcb', 'hex') | ||
let output = compile(compilerInput(revertStateContract.contract)) | ||
output = JSON.parse(output); | ||
const sources = { | ||
target: 'test.sol', | ||
sources: { 'test.sol': { content: revertStateContract.contract } } | ||
} | ||
const compilationResults = new CompilerAbstract('json', output, sources) | ||
const web3 = await (vmCall as any).getWeb3(); | ||
(vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, undefined, 0, output.contracts['test.sol']['MyContract'].evm.bytecode.object, function (error, hash) { | ||
if (error) { | ||
console.log(error) | ||
st.end(error) | ||
} else { | ||
web3.eth.getTransactionReceipt(hash) | ||
.then(tx => { | ||
// const storage = await this.vm.stateManager.dumpStorage(data.to) | ||
// web3.eth.getCode(tx.contractAddress).then((code) => console.log('code:---', code)) | ||
// (vmCall as any).web3().debug.traceTransaction(hash).then((code) => console.log('trace:', code)) | ||
testRevertState(st, privateKey, tx.contractAddress, output, compilationResults, web3, cb) | ||
} | ||
// st.end() | ||
) | ||
.catch(error => { | ||
st.end(error) | ||
}) | ||
} | ||
}) | ||
} | ||
|
||
function testRevertState (st, privateKey, contractAddress, output, compilationResults, web3, cb) { | ||
// call to foo(22) | ||
(vmCall as any).sendTx(web3, { nonce: 1, privateKey: privateKey }, contractAddress, 0, '2fbebd380000000000000000000000000000000000000000000000000000000000000016', | ||
function (error, hash) { | ||
if (error) { | ||
console.log(error) | ||
st.end(error) | ||
} else { | ||
web3.eth.getTransaction(hash) | ||
.then(tx => { | ||
const traceManager = new TraceManager({ web3 }) | ||
const codeManager = new CodeManager(traceManager) | ||
codeManager.clear() | ||
console.log(compilationResults) | ||
const solidityProxy = new SolidityProxy({ | ||
getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), | ||
getCode: codeManager.getCode.bind(codeManager), | ||
compilationResult: () => compilationResults | ||
}) | ||
const debuggerEvent = new EventManager() | ||
const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }) | ||
callTree.event.register('callTreeBuildFailed', (error) => { | ||
st.fail(error) | ||
}) | ||
callTree.event.register('callTreeNotReady', (reason) => { | ||
st.fail(reason) | ||
}) | ||
callTree.event.register('callTreeReady', (scopes, scopeStarts) => { | ||
const storageViewer = new StorageViewer({ | ||
stepIndex: 120, | ||
tx: tx, | ||
address: contractAddress | ||
}, new StorageResolver({ web3 }), traceManager) | ||
const stateVars = stateDecoder.extractStateVariables('MyContract', output.sources) | ||
stateDecoder.decodeState(stateVars, storageViewer).then((result) => { | ||
// even if the call is reverted, the value still persist during the call exeecution | ||
st.equal(result['data'].value, '22') | ||
cb() | ||
}, (reason) => { | ||
console.log('fail') | ||
st.end(reason) | ||
}) | ||
}) | ||
|
||
traceManager.resolveTrace(tx).then(() => { | ||
debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) | ||
}).catch((error) => { | ||
st.fail(error) | ||
}) | ||
}) | ||
.catch(error => { | ||
console.log(error) | ||
st.end(error) | ||
}) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters