evm
Version:
An ethereum virtual machine (EVM) bytecode decompiler
67 lines (62 loc) • 2.37 kB
text/typescript
import EVM from '../classes/evm.class';
import Opcode from '../interfaces/opcode.interface';
import * as BigNumber from '../../node_modules/big-integer';
import stringify from '../utils/stringify';
export class JUMP {
readonly name: string;
readonly type?: string;
readonly wrapped: boolean;
readonly valid: boolean;
readonly location: any;
constructor(location: any, bad?: boolean) {
this.name = 'JUMP';
this.wrapped = false;
this.location = location;
this.valid = true;
if (bad) {
this.valid = false;
}
}
toString() {
if (!this.valid) {
return "revert(\"Bad jump destination\");";
} else {
return 'goto(' + stringify(this.location) + ');';
}
}
}
export default (opcode: Opcode, state: EVM): void => {
const jumpLocation = state.stack.pop();
if (!BigNumber.isInstance(jumpLocation)) {
state.halted = true;
state.instructions.push(new JUMP(jumpLocation, true));
} else {
const opcodes = state.getOpcodes();
const jumpLocationData = opcodes.find((o: any) => o.pc === jumpLocation.toJSNumber());
if (!jumpLocationData) {
state.halted = true;
state.instructions.push(new JUMP(jumpLocation, true));
} else {
const jumpIndex = opcodes.indexOf(jumpLocationData);
if (!(opcode.pc + ':' + jumpLocation.toJSNumber() in state.jumps)) {
if (!jumpLocationData || jumpLocationData.name !== 'JUMPDEST') {
state.halted = true;
state.instructions.push(new JUMP(jumpLocation, true));
} else if (
jumpLocationData &&
jumpIndex >= 0 &&
jumpLocationData.name === 'JUMPDEST'
) {
state.jumps[opcode.pc + ':' + jumpLocation.toJSNumber()] = true;
state.pc = jumpIndex;
} else {
state.halted = true;
state.instructions.push(new JUMP(jumpLocation, true));
}
} else {
state.halted = true;
state.instructions.push(new JUMP(jumpLocation));
}
}
}
};