parent
99e96be875
commit
b687a2befa
@ -0,0 +1,177 @@ |
|||||||
|
'use strict' |
||||||
|
var tape = require('tape') |
||||||
|
var remixLib = require('remix-lib') |
||||||
|
var remixCore = require('remix-core') |
||||||
|
var compilerInput = remixLib.helpers.compiler.compilerInput |
||||||
|
var vmCall = require('./vmCall') |
||||||
|
var Debugger = require('../src/Ethdebugger') |
||||||
|
var compiler = require('solc') |
||||||
|
|
||||||
|
tape('debug contract', function (t) { |
||||||
|
var privateKey = new Buffer('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex') |
||||||
|
var vm = vmCall.initVM(t, privateKey) |
||||||
|
var output = compiler.compileStandardWrapper(compilerInput(ballot)) |
||||||
|
output = JSON.parse(output) |
||||||
|
var web3VM = new remixLib.vm.Web3VMProvider() |
||||||
|
web3VM.setVM(vm) |
||||||
|
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['Ballot'].evm.bytecode.object, (error, txHash) => { |
||||||
|
if (error) { |
||||||
|
t.end(error) |
||||||
|
} else { |
||||||
|
web3VM.eth.getTransaction(txHash, (error, tx) => { |
||||||
|
if (error) { |
||||||
|
t.end(error) |
||||||
|
} else { |
||||||
|
var debugManager = new Debugger({ |
||||||
|
compilationResult: function () { |
||||||
|
return output |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
debugManager.addProvider('web3vmprovider', web3VM) |
||||||
|
debugManager.switchProvider('web3vmprovider') |
||||||
|
|
||||||
|
debugManager.callTree.event.register('callTreeReady', () => { |
||||||
|
testDebugging(t, debugManager) |
||||||
|
}) |
||||||
|
|
||||||
|
debugManager.debug(tx) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
function testDebugging (t, debugManager) { |
||||||
|
// stack
|
||||||
|
debugManager.traceManager.getStackAt(4, (error, callstack) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
t.equal(JSON.stringify(callstack), JSON.stringify([ '0x0000000000000000000000000000000000000000000000000000000000000000' ])) |
||||||
|
}) |
||||||
|
|
||||||
|
debugManager.traceManager.getStackAt(41, (error, callstack) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
|
||||||
|
/* |
||||||
|
t.equal(JSON.stringify(callstack), JSON.stringify(['0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000004b0897b0513fdc7c541b6d9d7e929c4e5364d2db', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000001', '0x000000000000000000000000000000000000000000000000000000000000002d'])) |
||||||
|
*/ |
||||||
|
}) |
||||||
|
|
||||||
|
// storage
|
||||||
|
debugManager.traceManager.getCurrentCalledAddressAt(38, (error, address) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
var storageView = debugManager.storageViewAt(38, address) |
||||||
|
storageView.storageRange((error, storage) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
t.equal(JSON.stringify(storage), JSON.stringify({ '0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563': { key: '0x0000000000000000000000000000000000000000000000000000000000000000', value: '0x0000000000000000000000004b0897b0513fdc7c541b6d9d7e929c4e5364d2db' } })) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
debugManager.extractStateAt(138, (error, state) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
debugManager.decodeStateAt(138, state, (error, decodedState) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
t.equal(decodedState['chairperson'].value, '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB') |
||||||
|
t.equal(decodedState['chairperson'].type, 'address') |
||||||
|
t.equal(decodedState['proposals'].value[0].value.voteCount.value, '0') |
||||||
|
t.equal(decodedState['proposals'].value[0].value.voteCount.type, 'uint256') |
||||||
|
t.equal(decodedState['proposals'].value[0].type, 'struct Ballot.Proposal') |
||||||
|
t.equal(decodedState['proposals'].length, '0x1') |
||||||
|
t.equal(decodedState['proposals'].type, 'struct Ballot.Proposal[]') |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
debugManager.traceManager.getCurrentCalledAddressAt(138, (error, address) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
debugManager.sourceLocationFromVMTraceIndex(address, 138, (error, location) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
debugManager.decodeLocalsAt(138, location, (error, decodedlocals) => { |
||||||
|
if (error) return t.end(error) |
||||||
|
t.equal(JSON.stringify(decodedlocals), JSON.stringify({'p': {'value': '45', 'type': 'uint256'}, 'addressLocal': {'value': '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB', 'type': 'address'}, 'proposalsLocals': {'value': [{'value': {'voteCount': {'value': '0', 'type': 'uint256'}}, 'type': 'struct Ballot.Proposal'}], 'length': '0x1', 'type': 'struct Ballot.Proposal[]'}})) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
var sourceMappingDecoder = new remixLib.SourceMappingDecoder() |
||||||
|
var breakPointManager = new remixCore.code.BreakpointManager(debugManager, (rawLocation) => { |
||||||
|
return sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, ballot) |
||||||
|
}) |
||||||
|
|
||||||
|
breakPointManager.add({fileName: 'test.sol', row: 24}) |
||||||
|
|
||||||
|
breakPointManager.event.register('breakpointHit', function (sourceLocation, step) { |
||||||
|
t.equal(sourceLocation, '') |
||||||
|
t.equal(step, 67) |
||||||
|
}) |
||||||
|
breakPointManager.jumpNextBreakpoint(true) |
||||||
|
} |
||||||
|
|
||||||
|
var ballot = `pragma solidity ^0.4.0;
|
||||||
|
contract Ballot { |
||||||
|
|
||||||
|
struct Voter { |
||||||
|
uint weight; |
||||||
|
bool voted; |
||||||
|
uint8 vote; |
||||||
|
address delegate; |
||||||
|
} |
||||||
|
struct Proposal { |
||||||
|
uint voteCount; |
||||||
|
} |
||||||
|
|
||||||
|
address chairperson; |
||||||
|
mapping(address => Voter) voters; |
||||||
|
Proposal[] proposals; |
||||||
|
|
||||||
|
/// Create a new ballot with $(_numProposals) different proposals.
|
||||||
|
function Ballot() public { |
||||||
|
uint p = 45; |
||||||
|
chairperson = msg.sender; |
||||||
|
address addressLocal = msg.sender; // copy of state variable
|
||||||
|
voters[chairperson].weight = 1; |
||||||
|
proposals.length = 1; |
||||||
|
Proposal[] proposalsLocals = proposals; // copy of state variable
|
||||||
|
} |
||||||
|
|
||||||
|
/// Give $(toVoter) the right to vote on this ballot.
|
||||||
|
/// May only be called by $(chairperson).
|
||||||
|
function giveRightToVote(address toVoter) public { |
||||||
|
if (msg.sender != chairperson || voters[toVoter].voted) return; |
||||||
|
voters[toVoter].weight = 1; |
||||||
|
} |
||||||
|
|
||||||
|
/// Delegate your vote to the voter $(to).
|
||||||
|
function delegate(address to) public { |
||||||
|
Voter storage sender = voters[msg.sender]; // assigns reference
|
||||||
|
if (sender.voted) return; |
||||||
|
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender) |
||||||
|
to = voters[to].delegate; |
||||||
|
if (to == msg.sender) return; |
||||||
|
sender.voted = true; |
||||||
|
sender.delegate = to; |
||||||
|
Voter storage delegateTo = voters[to]; |
||||||
|
if (delegateTo.voted) |
||||||
|
proposals[delegateTo.vote].voteCount += sender.weight; |
||||||
|
else |
||||||
|
delegateTo.weight += sender.weight; |
||||||
|
} |
||||||
|
|
||||||
|
/// Give a single vote to proposal $(toProposal).
|
||||||
|
function vote(uint8 toProposal) public { |
||||||
|
Voter storage sender = voters[msg.sender]; |
||||||
|
if (sender.voted || toProposal >= proposals.length) return; |
||||||
|
sender.voted = true; |
||||||
|
sender.vote = toProposal; |
||||||
|
proposals[toProposal].voteCount += sender.weight; |
||||||
|
} |
||||||
|
|
||||||
|
function winningProposal() public constant returns (uint8 _winningProposal) { |
||||||
|
uint256 winningVoteCount = 0; |
||||||
|
for (uint8 prop = 0; prop < proposals.length; prop++) |
||||||
|
if (proposals[prop].voteCount > winningVoteCount) { |
||||||
|
winningVoteCount = proposals[prop].voteCount; |
||||||
|
_winningProposal = prop; |
||||||
|
} |
||||||
|
} |
||||||
|
}` |
@ -0,0 +1,64 @@ |
|||||||
|
'use strict' |
||||||
|
var utileth = require('ethereumjs-util') |
||||||
|
var Tx = require('ethereumjs-tx') |
||||||
|
var Block = require('ethereumjs-block') |
||||||
|
var BN = require('ethereumjs-util').BN |
||||||
|
var remixLib = require('remix-lib') |
||||||
|
|
||||||
|
function sendTx (vm, from, to, value, data, cb) { |
||||||
|
var tx = new Tx({ |
||||||
|
nonce: new BN(from.nonce++), |
||||||
|
gasPrice: new BN(1), |
||||||
|
gasLimit: new BN(3000000, 10), |
||||||
|
to: to, |
||||||
|
value: new BN(value, 10), |
||||||
|
data: new Buffer(data, 'hex') |
||||||
|
}) |
||||||
|
tx.sign(from.privateKey) |
||||||
|
var block = new Block({ |
||||||
|
header: { |
||||||
|
timestamp: new Date().getTime() / 1000 | 0, |
||||||
|
number: 0 |
||||||
|
}, |
||||||
|
transactions: [], |
||||||
|
uncleHeaders: [] |
||||||
|
}) |
||||||
|
vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}, function (error, result) { |
||||||
|
setTimeout(() => { |
||||||
|
cb(error, utileth.bufferToHex(tx.hash())) |
||||||
|
}, 500) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
Init VM / Send Transaction |
||||||
|
*/ |
||||||
|
function initVM (st, privateKey) { |
||||||
|
var utileth = require('ethereumjs-util') |
||||||
|
var VM = require('ethereumjs-vm') |
||||||
|
var Web3Providers = remixLib.vm.Web3Providers |
||||||
|
var address = utileth.privateToAddress(privateKey) |
||||||
|
var vm = new VM({ |
||||||
|
enableHomestead: true, |
||||||
|
activatePrecompiles: true |
||||||
|
}) |
||||||
|
vm.stateManager.putAccountBalance(address, 'f00000000000000001', function cb () {}) |
||||||
|
var web3Providers = new Web3Providers() |
||||||
|
web3Providers.addVM('VM', vm) |
||||||
|
web3Providers.get('VM', function (error, obj) { |
||||||
|
if (error) { |
||||||
|
var mes = 'provider TEST not defined' |
||||||
|
console.log(mes) |
||||||
|
st.fail(mes) |
||||||
|
} else { |
||||||
|
remixLib.global.web3 = obj |
||||||
|
remixLib.global.web3Debug = obj |
||||||
|
} |
||||||
|
}) |
||||||
|
return vm |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
sendTx: sendTx, |
||||||
|
initVM: initVM |
||||||
|
} |
Loading…
Reference in new issue