@tact-lang/opcode
Advanced tools
Comparing version 0.0.5 to 0.0.6
@@ -8,2 +8,7 @@ # Changelog | ||
## [0.0.6] - 2023-03-24 | ||
## Fixed | ||
- Fix invalid cell hash and offset in dict-based parser | ||
## [0.0.5] - 2023-03-24 | ||
@@ -10,0 +15,0 @@ |
@@ -53,3 +53,3 @@ "use strict"; | ||
}); | ||
extracted.set(name, { ref: true, rendered: w.end(), src: cell }); | ||
extracted.set(name, { ref: true, rendered: w.end(), src: cell, srcOffset: 0 }); | ||
return name; | ||
@@ -59,2 +59,3 @@ } | ||
let name = knownMethods_1.knownMethods[key] || '?fun_' + (unknownIndex++); | ||
let body = value.cell.beginParse().skip(value.offset).asCell(); | ||
let w = new Writer_1.Writer(); | ||
@@ -64,3 +65,3 @@ w.inIndent(() => { | ||
decompileCell({ | ||
src: value, | ||
src: body, | ||
root: false, | ||
@@ -73,3 +74,8 @@ writer: w, | ||
}); | ||
extracted.set(name, { ref: false, rendered: w.end(), src: value }); | ||
extracted.set(name, { | ||
ref: false, | ||
rendered: w.end(), | ||
src: value.cell, | ||
srcOffset: value.offset | ||
}); | ||
} | ||
@@ -85,3 +91,3 @@ // Render methods | ||
let opstr = `${key} ${value.ref ? 'PROCREF' : 'PROC'}:<{`; | ||
writer.append(printer({ op: opstr, offset: 0, length: 0, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent)); | ||
writer.inIndent(() => { | ||
@@ -93,3 +99,3 @@ value.rendered.split('\n').forEach(line => { | ||
opstr = `}>`; | ||
writer.append(printer({ op: opstr, offset: 0, length: 0, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent)); | ||
} | ||
@@ -106,3 +112,3 @@ }); | ||
let opstr = `${id} INLINECALLDICT`; | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
continue; | ||
@@ -119,3 +125,3 @@ } | ||
let opstr = '<{'; | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
writer.inIndent(() => { | ||
@@ -131,3 +137,3 @@ decompileCell({ | ||
opstr = '}> ' + op.op.code; | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
continue; | ||
@@ -142,3 +148,3 @@ } | ||
let opstr = (0, opcodeToString_1.opcodeToString)(op.op); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
} | ||
@@ -168,8 +174,17 @@ } | ||
serialize: (src, builder) => { | ||
return builder.storeSlice(src.beginParse()); | ||
throw Error('Not implemented'); | ||
}, | ||
parse: (src) => { | ||
return src.asCell(); | ||
let bitsReader = src._reader.clone(); | ||
let offset = bitsReader._offset; | ||
bitsReader.reset(); | ||
let bits = bitsReader.loadBits(bitsReader.remaining); | ||
let b = (0, ton_core_1.beginCell)() | ||
.storeBits(bits); | ||
while (src.remainingRefs > 0) { | ||
b.storeRef(src.loadRef()); | ||
} | ||
return { offset, cell: b.endCell() }; | ||
} | ||
}; | ||
} |
/// <reference types="node" /> | ||
import { Cell } from "ton-core"; | ||
import { Cell, Slice } from "ton-core"; | ||
import { OpCode } from "../codepage/opcodes.gen"; | ||
@@ -14,4 +14,4 @@ export type DecompiledOpCode = OpCode | { | ||
export declare function decompile(args: { | ||
src: Cell | Buffer; | ||
src: Cell | Slice | Buffer; | ||
allowUnknown?: boolean; | ||
}): DecompiledInstruction[]; |
@@ -7,14 +7,16 @@ "use strict"; | ||
function decompile(args) { | ||
// Load cell | ||
let cell; | ||
// Result collection | ||
let result = []; | ||
// Load slice | ||
let sc; | ||
if (Buffer.isBuffer(args.src)) { | ||
cell = ton_core_1.Cell.fromBoc(args.src)[0]; | ||
sc = ton_core_1.Cell.fromBoc(args.src)[0].beginParse(); | ||
} | ||
else if (args.src instanceof ton_core_1.Cell) { | ||
sc = args.src.beginParse(); | ||
} | ||
else { | ||
cell = args.src; | ||
sc = args.src; | ||
} | ||
// Result collection | ||
let result = []; | ||
// Parse cell | ||
let sc = cell.beginParse(); | ||
let scl = sc.remainingBits; | ||
@@ -21,0 +23,0 @@ let sco = 0; |
@@ -0,4 +1,6 @@ | ||
import { Cell } from "ton-core"; | ||
export type Printer = (src: string | { | ||
op: string; | ||
hash: string; | ||
cell: Cell; | ||
offset: number; | ||
@@ -5,0 +7,0 @@ length: number; |
{ | ||
"name": "@tact-lang/opcode", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"main": "dist/index.js", | ||
@@ -5,0 +5,0 @@ "repository": "https://github.com/tact-lang/ton-opcode.git", |
@@ -29,2 +29,8 @@ import { decompileAll } from "./decompileAll"; | ||
it('should decompile highload wallet', () => { | ||
let wallet = Buffer.from('te6ccgEBCAEAlwABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQC48oMI1xgg0x/TH9MfAvgju/Jj7UTQ0x/TH9P/0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhYhgBD0eG+lIJgC0wfUMAH7AJEy4gGz5lsBpMjLH8sfy//J7VQABNAwAgFIBgcAF7s5ztRNDTPzHXC/+AARuMl+1E0NcLH4', 'base64'); | ||
let res = decompileAll({ src: wallet }); | ||
expect(res).toMatchSnapshot(); | ||
}); | ||
it('should decompile wallet v4 speedtest', () => { | ||
@@ -31,0 +37,0 @@ const wallet = Buffer.from('te6ccgECFAEAAtQAART/APSkE/S88sgLAQIBIAIDAgFIBAUE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8QERITAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNBgcCASAICQB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+gIZ9ADLaRfLH1Jgyz8gyYBA+wAGAIpQBIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UAXKwjiOCEGRzdHKDHrFwgBhQBcsFUAPPFiP6AhPLassfyz/JgED7AJJfA+ICASAKCwBZvSQrb2omhAgKBrkPoCGEcNQICEekk30pkQzmkD6f+YN4EoAbeBAUiYcVnzGEAgFYDA0AEbjJftRNDXCx+AA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA4PABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AAG7SB/oA1NQi+QAFyMoHFcv/ydB3dIAYyMsFywIizxZQBfoCFMtrEszMyXP7AMhAFIEBCPRR8qcCAHCBAQjXGPoA0z/IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBsgQEI1xj6ANM/MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAAr0AMntVA==', 'base64'); |
@@ -1,2 +0,2 @@ | ||
import { Cell, Dictionary, DictionaryValue } from "ton-core"; | ||
import { beginCell, BitReader, Cell, Dictionary, DictionaryValue } from "ton-core"; | ||
import { opcodeToString } from "../codepage/opcodeToString"; | ||
@@ -33,7 +33,7 @@ import { Maybe } from "../utils/maybe"; | ||
let dictCell = opcodes[1].op.args[1]; | ||
let dict = Dictionary.loadDirect<number, Cell>(Dictionary.Keys.Int(dictKeyLen), createCodeCell(), dictCell); | ||
let dict = Dictionary.loadDirect<number, { offset: number, cell: Cell }>(Dictionary.Keys.Int(dictKeyLen), createCodeCell(), dictCell); | ||
// Extract all methods | ||
let unknownIndex = 0; | ||
let extracted = new Map<string, { ref: boolean, rendered: string, src: Cell }>(); | ||
let extracted = new Map<string, { ref: boolean, rendered: string, src: Cell, srcOffset: number }>(); | ||
let callRefs = new Map<string, string>(); | ||
@@ -65,3 +65,3 @@ function extract(cell: Cell) { | ||
}); | ||
extracted.set(name, { ref: true, rendered: w.end(), src: cell }); | ||
extracted.set(name, { ref: true, rendered: w.end(), src: cell, srcOffset: 0 }); | ||
return name; | ||
@@ -71,2 +71,3 @@ } | ||
let name = knownMethods[key] || '?fun_' + (unknownIndex++); | ||
let body = value.cell.beginParse().skip(value.offset).asCell(); | ||
let w = new Writer(); | ||
@@ -76,3 +77,3 @@ w.inIndent(() => { | ||
decompileCell({ | ||
src: value, | ||
src: body, | ||
root: false, | ||
@@ -85,3 +86,8 @@ writer: w, | ||
}); | ||
extracted.set(name, { ref: false, rendered: w.end(), src: value }); | ||
extracted.set(name, { | ||
ref: false, | ||
rendered: w.end(), | ||
src: value.cell, | ||
srcOffset: value.offset | ||
}); | ||
} | ||
@@ -98,3 +104,3 @@ | ||
let opstr = `${key} ${value.ref ? 'PROCREF' : 'PROC'}:<{`; | ||
writer.append(printer({ op: opstr, offset: 0, length: 0, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent)); | ||
writer.inIndent(() => { | ||
@@ -106,3 +112,3 @@ value.rendered.split('\n').forEach(line => { | ||
opstr = `}>`; | ||
writer.append(printer({ op: opstr, offset: 0, length: 0, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent)); | ||
} | ||
@@ -121,3 +127,3 @@ }); | ||
let opstr = `${id} INLINECALLDICT`; | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
continue; | ||
@@ -135,3 +141,3 @@ } | ||
let opstr = '<{'; | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
writer.inIndent(() => { | ||
@@ -147,3 +153,3 @@ decompileCell({ | ||
opstr = '}> ' + op.op.code; | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
continue; | ||
@@ -160,3 +166,3 @@ } | ||
let opstr = opcodeToString(op.op); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash }, writer.indent)); | ||
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent)); | ||
} | ||
@@ -183,11 +189,20 @@ } | ||
function createCodeCell(): DictionaryValue<Cell> { | ||
function createCodeCell(): DictionaryValue<{ offset: number, cell: Cell }> { | ||
return { | ||
serialize: (src, builder) => { | ||
return builder.storeSlice(src.beginParse()); | ||
throw Error('Not implemented'); | ||
}, | ||
parse: (src) => { | ||
return src.asCell(); | ||
let bitsReader = ((src as any)._reader.clone() as BitReader); | ||
let offset = (bitsReader as any)._offset as number; | ||
bitsReader.reset(); | ||
let bits = bitsReader.loadBits(bitsReader.remaining); | ||
let b = beginCell() | ||
.storeBits(bits); | ||
while (src.remainingRefs > 0) { | ||
b.storeRef(src.loadRef()); | ||
} | ||
return { offset, cell: b.endCell() }; | ||
} | ||
}; | ||
} |
@@ -22,6 +22,5 @@ import { Cell } from "ton-core"; | ||
let res = decompile({ src: wallet }); | ||
console.warn(res); | ||
// console.warn(original); | ||
expect(res).toMatchSnapshot(); | ||
} | ||
}); | ||
}); |
@@ -1,2 +0,2 @@ | ||
import { beginCell, Cell } from "ton-core"; | ||
import { beginCell, Cell, Slice } from "ton-core"; | ||
import { loadOpcode } from "../codepage/loadOpcode"; | ||
@@ -12,17 +12,18 @@ import { OpCode } from "../codepage/opcodes.gen"; | ||
export function decompile(args: { src: Cell | Buffer, allowUnknown?: boolean }): DecompiledInstruction[] { | ||
export function decompile(args: { src: Cell | Slice | Buffer, allowUnknown?: boolean }): DecompiledInstruction[] { | ||
// Load cell | ||
let cell: Cell; | ||
// Result collection | ||
let result: DecompiledInstruction[] = []; | ||
// Load slice | ||
let sc: Slice; | ||
if (Buffer.isBuffer(args.src)) { | ||
cell = Cell.fromBoc(args.src)[0]; | ||
sc = Cell.fromBoc(args.src)[0].beginParse(); | ||
} else if (args.src instanceof Cell) { | ||
sc = args.src.beginParse(); | ||
} else { | ||
cell = args.src; | ||
sc = args.src; | ||
} | ||
// Result collection | ||
let result: DecompiledInstruction[] = []; | ||
// Parse cell | ||
let sc = cell.beginParse(); | ||
let scl = sc.remainingBits; | ||
@@ -29,0 +30,0 @@ let sco = 0; |
@@ -1,3 +0,5 @@ | ||
export type Printer = (src: string | { op: string, hash: string, offset: number, length: number }, indent: number) => string; | ||
import { Cell } from "ton-core"; | ||
export type Printer = (src: string | { op: string, hash: string, cell: Cell, offset: number, length: number }, indent: number) => string; | ||
export function createTextPrinter(indentWidth: number): Printer { | ||
@@ -4,0 +6,0 @@ return (src, indent) => { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6054061
63
5864