Skip to content

Commit

Permalink
disasm: Add experimental CBOR parsing for EVM metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
shazow committed Nov 1, 2024
1 parent 35192af commit 215a828
Showing 1 changed file with 20 additions and 11 deletions.
31 changes: 20 additions & 11 deletions src/disasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ABI, ABIFunction, ABIEvent, StateMutability } from "./abi.js";
import type { OpCode } from "./opcodes.js";
import type { ProxyResolver } from "./proxies.js";

import { hexToBytes, bytesToHex } from "./utils.js";
import { hexToBytes, bytesToHex, cborMapDecoder } from "./utils.js";

import { opcodes, pushWidth, isPush, isLog, isHalt, isCompare } from "./opcodes.js";

Expand Down Expand Up @@ -154,6 +154,7 @@ export class Program {
proxySlots: Array<string>; // PUSH32 found that match known proxy slots
proxies: Array<ProxyResolver>;
isFactory: boolean; // CREATE or CREATE2 detected
metadata: Record<string, string>; // CBOR metadata at the end of the contract

init?: Program; // Program embedded as init code

Expand Down Expand Up @@ -517,22 +518,30 @@ export function disasm(bytecode: string, config?: {onlyJumpTable: boolean}): Pro
}
}

let endBoundary : number|undefined = undefined;
const finalByte = code.bytecode.slice(-1)[0];
// Try to detect CBOR metadata (vs bytecode that does not include it)
// https://playground.sourcify.dev/
if (!isHalt(finalByte) || code.bytecode.slice(-2)[0] === 0) {
const cborLength = valueToOffset(code.bytecode.slice(-2));
endBoundary = -(cborLength + 2); // +4 for the length bytes
const cborData = code.bytecode.slice(endBoundary).slice(0, -2);

if (cborData.length === 51) {
// We're going to cheat if we suspect it's {ipfs, solc}
p.metadata = {
ipfs: bytesToHex(cborData.slice(8, 42)), // 2 bytes map + 6 bytes "ipfs" for 34 bytes value
solc: bytesToHex(cborData.slice(48, 51)), // 2 bytes map + 6 bytes "solc" for 3 bytes value
}
}
}

if ((boundaryPos > 0 && p.proxies.length === 0)) {
// Slots could be stored outside of the program boundary and copied in
// and we haven't found any proxy slots yet so let's check just in case...
// This is unstructured data, so it could be anything. We can't parse it reliably.

// We can skip the CBOR encoding based on length defined in the final byte
// https://playground.sourcify.dev/

// TODO: Pull CBOR out and add to result
let endBoundary : number|undefined = undefined;
const finalByte = code.bytecode.slice(-1)[0];
if (!isHalt(finalByte)) {
const cborLength = valueToOffset(code.bytecode.slice(-2));
endBoundary = -(cborLength + 4); // +4 for the length bytes
}

const auxData = bytesToHex(code.bytecode.slice(boundaryPos, endBoundary));
if (auxData.length > 2) { // 0x is empty
// Look for known slots in extra data segment that could be CODECOPY'd
Expand Down

0 comments on commit 215a828

Please sign in to comment.