glamsterdam-compat-lab 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +59 -0
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/ROADMAP.md +76 -0
- package/SECURITY.md +19 -0
- package/data/client-compat/clients.example.json +42 -0
- package/data/detectors/thresholds.ci.json +33 -0
- package/data/detectors/thresholds.json +33 -0
- package/data/detectors/thresholds.research.json +33 -0
- package/data/eips/glamsterdam.json +85 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +163 -0
- package/dist/cli.js.map +1 -0
- package/dist/detectors/balDetectors.d.ts +3 -0
- package/dist/detectors/balDetectors.js +26 -0
- package/dist/detectors/balDetectors.js.map +1 -0
- package/dist/detectors/contractSizeDetectors.d.ts +3 -0
- package/dist/detectors/contractSizeDetectors.js +37 -0
- package/dist/detectors/contractSizeDetectors.js.map +1 -0
- package/dist/detectors/epbsDetectors.d.ts +7 -0
- package/dist/detectors/epbsDetectors.js +33 -0
- package/dist/detectors/epbsDetectors.js.map +1 -0
- package/dist/detectors/gasRepricingDetectors.d.ts +4 -0
- package/dist/detectors/gasRepricingDetectors.js +135 -0
- package/dist/detectors/gasRepricingDetectors.js.map +1 -0
- package/dist/detectors/nativeEthTransferLogDetectors.d.ts +8 -0
- package/dist/detectors/nativeEthTransferLogDetectors.js +54 -0
- package/dist/detectors/nativeEthTransferLogDetectors.js.map +1 -0
- package/dist/detectors/stateCreationDetectors.d.ts +4 -0
- package/dist/detectors/stateCreationDetectors.js +46 -0
- package/dist/detectors/stateCreationDetectors.js.map +1 -0
- package/dist/detectors/thresholds.d.ts +34 -0
- package/dist/detectors/thresholds.js +45 -0
- package/dist/detectors/thresholds.js.map +1 -0
- package/dist/detectors/types.d.ts +15 -0
- package/dist/detectors/types.js +23 -0
- package/dist/detectors/types.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/eipRegistry.d.ts +6 -0
- package/dist/registry/eipRegistry.js +30 -0
- package/dist/registry/eipRegistry.js.map +1 -0
- package/dist/registry/schemas.d.ts +76 -0
- package/dist/registry/schemas.js +34 -0
- package/dist/registry/schemas.js.map +1 -0
- package/dist/reports/jsonReporter.d.ts +2 -0
- package/dist/reports/jsonReporter.js +5 -0
- package/dist/reports/jsonReporter.js.map +1 -0
- package/dist/reports/markdownReporter.d.ts +2 -0
- package/dist/reports/markdownReporter.js +75 -0
- package/dist/reports/markdownReporter.js.map +1 -0
- package/dist/reports/reportTypes.d.ts +150 -0
- package/dist/reports/reportTypes.js +111 -0
- package/dist/reports/reportTypes.js.map +1 -0
- package/dist/scanners/bytecodeScanner.d.ts +11 -0
- package/dist/scanners/bytecodeScanner.js +107 -0
- package/dist/scanners/bytecodeScanner.js.map +1 -0
- package/dist/scanners/indexerScanner.d.ts +13 -0
- package/dist/scanners/indexerScanner.js +129 -0
- package/dist/scanners/indexerScanner.js.map +1 -0
- package/dist/scanners/rpcTraceScanner.d.ts +40 -0
- package/dist/scanners/rpcTraceScanner.js +121 -0
- package/dist/scanners/rpcTraceScanner.js.map +1 -0
- package/dist/scanners/traceScanner.d.ts +24 -0
- package/dist/scanners/traceScanner.js +272 -0
- package/dist/scanners/traceScanner.js.map +1 -0
- package/dist/scanners/validatorScanner.d.ts +40 -0
- package/dist/scanners/validatorScanner.js +210 -0
- package/dist/scanners/validatorScanner.js.map +1 -0
- package/dist/utils/bytecode.d.ts +11 -0
- package/dist/utils/bytecode.js +140 -0
- package/dist/utils/bytecode.js.map +1 -0
- package/dist/utils/files.d.ts +10 -0
- package/dist/utils/files.js +51 -0
- package/dist/utils/files.js.map +1 -0
- package/dist/utils/severity.d.ts +2 -0
- package/dist/utils/severity.js +13 -0
- package/dist/utils/severity.js.map +1 -0
- package/docs/fixtures.md +60 -0
- package/docs/release.md +132 -0
- package/examples/storage-heavy-bytecode.md +57 -0
- package/fixtures/bytecode/storage-heavy.hex +1 -0
- package/fixtures/indexers/balance-diff-indexer.json +15 -0
- package/fixtures/indexers/subgraph.yaml +24 -0
- package/fixtures/traces/besu-debug-structlogs.json +18 -0
- package/fixtures/traces/call-tracer-tree.json +27 -0
- package/fixtures/traces/drpc-call-tracer-real.json +373 -0
- package/fixtures/traces/erigon-action-trace.json +29 -0
- package/fixtures/traces/foundry-json-trace.json +19 -0
- package/fixtures/traces/geth-json-rpc-structlogs.json +16 -0
- package/fixtures/traces/hardhat-debug-trace.json +13 -0
- package/fixtures/traces/nethermind-debug-structlogs.json +17 -0
- package/fixtures/traces/storage-heavy-trace.json +25 -0
- package/fixtures/validator/operator-config.yaml +15 -0
- package/package.json +80 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
const opcodeNames = new Map([
|
|
2
|
+
[0x00, "STOP"],
|
|
3
|
+
[0x01, "ADD"],
|
|
4
|
+
[0x02, "MUL"],
|
|
5
|
+
[0x03, "SUB"],
|
|
6
|
+
[0x04, "DIV"],
|
|
7
|
+
[0x05, "SDIV"],
|
|
8
|
+
[0x06, "MOD"],
|
|
9
|
+
[0x07, "SMOD"],
|
|
10
|
+
[0x08, "ADDMOD"],
|
|
11
|
+
[0x09, "MULMOD"],
|
|
12
|
+
[0x0a, "EXP"],
|
|
13
|
+
[0x0b, "SIGNEXTEND"],
|
|
14
|
+
[0x10, "LT"],
|
|
15
|
+
[0x11, "GT"],
|
|
16
|
+
[0x12, "SLT"],
|
|
17
|
+
[0x13, "SGT"],
|
|
18
|
+
[0x14, "EQ"],
|
|
19
|
+
[0x15, "ISZERO"],
|
|
20
|
+
[0x16, "AND"],
|
|
21
|
+
[0x17, "OR"],
|
|
22
|
+
[0x18, "XOR"],
|
|
23
|
+
[0x19, "NOT"],
|
|
24
|
+
[0x1a, "BYTE"],
|
|
25
|
+
[0x1b, "SHL"],
|
|
26
|
+
[0x1c, "SHR"],
|
|
27
|
+
[0x1d, "SAR"],
|
|
28
|
+
[0x20, "SHA3"],
|
|
29
|
+
[0x30, "ADDRESS"],
|
|
30
|
+
[0x31, "BALANCE"],
|
|
31
|
+
[0x32, "ORIGIN"],
|
|
32
|
+
[0x33, "CALLER"],
|
|
33
|
+
[0x34, "CALLVALUE"],
|
|
34
|
+
[0x35, "CALLDATALOAD"],
|
|
35
|
+
[0x36, "CALLDATASIZE"],
|
|
36
|
+
[0x37, "CALLDATACOPY"],
|
|
37
|
+
[0x38, "CODESIZE"],
|
|
38
|
+
[0x39, "CODECOPY"],
|
|
39
|
+
[0x3a, "GASPRICE"],
|
|
40
|
+
[0x3b, "EXTCODESIZE"],
|
|
41
|
+
[0x3c, "EXTCODECOPY"],
|
|
42
|
+
[0x3d, "RETURNDATASIZE"],
|
|
43
|
+
[0x3e, "RETURNDATACOPY"],
|
|
44
|
+
[0x3f, "EXTCODEHASH"],
|
|
45
|
+
[0x40, "BLOCKHASH"],
|
|
46
|
+
[0x41, "COINBASE"],
|
|
47
|
+
[0x42, "TIMESTAMP"],
|
|
48
|
+
[0x43, "NUMBER"],
|
|
49
|
+
[0x44, "PREVRANDAO"],
|
|
50
|
+
[0x45, "GASLIMIT"],
|
|
51
|
+
[0x46, "CHAINID"],
|
|
52
|
+
[0x47, "SELFBALANCE"],
|
|
53
|
+
[0x48, "BASEFEE"],
|
|
54
|
+
[0x49, "BLOBHASH"],
|
|
55
|
+
[0x4a, "BLOBBASEFEE"],
|
|
56
|
+
[0x50, "POP"],
|
|
57
|
+
[0x51, "MLOAD"],
|
|
58
|
+
[0x52, "MSTORE"],
|
|
59
|
+
[0x53, "MSTORE8"],
|
|
60
|
+
[0x54, "SLOAD"],
|
|
61
|
+
[0x55, "SSTORE"],
|
|
62
|
+
[0x56, "JUMP"],
|
|
63
|
+
[0x57, "JUMPI"],
|
|
64
|
+
[0x58, "PC"],
|
|
65
|
+
[0x59, "MSIZE"],
|
|
66
|
+
[0x5a, "GAS"],
|
|
67
|
+
[0x5b, "JUMPDEST"],
|
|
68
|
+
[0x5f, "PUSH0"],
|
|
69
|
+
[0xf0, "CREATE"],
|
|
70
|
+
[0xf1, "CALL"],
|
|
71
|
+
[0xf2, "CALLCODE"],
|
|
72
|
+
[0xf3, "RETURN"],
|
|
73
|
+
[0xf4, "DELEGATECALL"],
|
|
74
|
+
[0xf5, "CREATE2"],
|
|
75
|
+
[0xfa, "STATICCALL"],
|
|
76
|
+
[0xfd, "REVERT"],
|
|
77
|
+
[0xfe, "INVALID"],
|
|
78
|
+
[0xff, "SELFDESTRUCT"]
|
|
79
|
+
]);
|
|
80
|
+
for (let opcode = 0x60; opcode <= 0x7f; opcode += 1) {
|
|
81
|
+
opcodeNames.set(opcode, `PUSH${opcode - 0x5f}`);
|
|
82
|
+
}
|
|
83
|
+
for (let opcode = 0x80; opcode <= 0x8f; opcode += 1) {
|
|
84
|
+
opcodeNames.set(opcode, `DUP${opcode - 0x7f}`);
|
|
85
|
+
}
|
|
86
|
+
for (let opcode = 0x90; opcode <= 0x9f; opcode += 1) {
|
|
87
|
+
opcodeNames.set(opcode, `SWAP${opcode - 0x8f}`);
|
|
88
|
+
}
|
|
89
|
+
for (let opcode = 0xa0; opcode <= 0xa4; opcode += 1) {
|
|
90
|
+
opcodeNames.set(opcode, `LOG${opcode - 0xa0}`);
|
|
91
|
+
}
|
|
92
|
+
export function normalizeBytecode(input) {
|
|
93
|
+
const compact = input.replace(/\s+/g, "").toLowerCase();
|
|
94
|
+
const withoutPrefix = compact.startsWith("0x") ? compact.slice(2) : compact;
|
|
95
|
+
if (withoutPrefix.length === 0) {
|
|
96
|
+
return "0x";
|
|
97
|
+
}
|
|
98
|
+
if (!/^[0-9a-f]+$/.test(withoutPrefix)) {
|
|
99
|
+
throw new Error("Input is not valid hexadecimal bytecode");
|
|
100
|
+
}
|
|
101
|
+
const evenHex = withoutPrefix.length % 2 === 0 ? withoutPrefix : `0${withoutPrefix}`;
|
|
102
|
+
return `0x${evenHex}`;
|
|
103
|
+
}
|
|
104
|
+
export function byteLength(bytecode) {
|
|
105
|
+
const normalized = normalizeBytecode(bytecode);
|
|
106
|
+
return (normalized.length - 2) / 2;
|
|
107
|
+
}
|
|
108
|
+
export function disassembleBytecode(bytecode) {
|
|
109
|
+
const normalized = normalizeBytecode(bytecode).slice(2);
|
|
110
|
+
const bytes = normalized.match(/.{1,2}/g)?.map((hex) => Number.parseInt(hex, 16)) ?? [];
|
|
111
|
+
const opcodes = [];
|
|
112
|
+
for (let pc = 0; pc < bytes.length; pc += 1) {
|
|
113
|
+
const code = bytes[pc] ?? 0;
|
|
114
|
+
const name = opcodeNames.get(code) ?? `UNKNOWN_0x${code.toString(16).padStart(2, "0")}`;
|
|
115
|
+
if (code >= 0x60 && code <= 0x7f) {
|
|
116
|
+
const pushBytes = code - 0x5f;
|
|
117
|
+
const dataStart = pc + 1;
|
|
118
|
+
const dataEnd = Math.min(dataStart + pushBytes, bytes.length);
|
|
119
|
+
const pushData = bytes.slice(dataStart, dataEnd).map(toHexByte).join("");
|
|
120
|
+
opcodes.push({ pc, code, name, pushData });
|
|
121
|
+
pc += pushBytes;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
opcodes.push({ pc, code, name });
|
|
125
|
+
}
|
|
126
|
+
return opcodes;
|
|
127
|
+
}
|
|
128
|
+
export function countOpcodeNames(opcodes) {
|
|
129
|
+
return opcodes.reduce((counts, opcode) => {
|
|
130
|
+
counts[opcode.name] = (counts[opcode.name] ?? 0) + 1;
|
|
131
|
+
return counts;
|
|
132
|
+
}, {});
|
|
133
|
+
}
|
|
134
|
+
export function opcodeCount(counts, names) {
|
|
135
|
+
return names.reduce((total, name) => total + (counts[name] ?? 0), 0);
|
|
136
|
+
}
|
|
137
|
+
function toHexByte(value) {
|
|
138
|
+
return value.toString(16).padStart(2, "0");
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=bytecode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bytecode.js","sourceRoot":"","sources":["../../src/utils/bytecode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function isReadableFile(value: string): boolean;
|
|
2
|
+
export declare function readPathOrValue(pathOrValue: string): {
|
|
3
|
+
text: string;
|
|
4
|
+
name: string;
|
|
5
|
+
isFile: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function readTextFile(filePath: string): string;
|
|
8
|
+
export declare function loadStructuredFile(filePath: string): unknown;
|
|
9
|
+
export declare function parseStructuredText(text: string, sourceName?: string): unknown;
|
|
10
|
+
export declare function resolveFromCwd(pathLike: string): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { extname, resolve } from "node:path";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
export function isReadableFile(value) {
|
|
5
|
+
try {
|
|
6
|
+
return existsSync(value) && statSync(value).isFile();
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function readPathOrValue(pathOrValue) {
|
|
13
|
+
if (!isReadableFile(pathOrValue)) {
|
|
14
|
+
return {
|
|
15
|
+
text: pathOrValue,
|
|
16
|
+
name: "inline-bytecode",
|
|
17
|
+
isFile: false
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
text: readFileSync(pathOrValue, "utf8"),
|
|
22
|
+
name: pathOrValue,
|
|
23
|
+
isFile: true
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function readTextFile(filePath) {
|
|
27
|
+
return readFileSync(filePath, "utf8");
|
|
28
|
+
}
|
|
29
|
+
export function loadStructuredFile(filePath) {
|
|
30
|
+
const text = readTextFile(filePath);
|
|
31
|
+
return parseStructuredText(text, filePath);
|
|
32
|
+
}
|
|
33
|
+
export function parseStructuredText(text, sourceName = "input") {
|
|
34
|
+
const ext = extname(sourceName).toLowerCase();
|
|
35
|
+
if (ext === ".yaml" || ext === ".yml") {
|
|
36
|
+
return YAML.parse(text) ?? {};
|
|
37
|
+
}
|
|
38
|
+
if (ext === ".json") {
|
|
39
|
+
return JSON.parse(text);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(text);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return YAML.parse(text) ?? {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function resolveFromCwd(pathLike) {
|
|
49
|
+
return resolve(process.cwd(), pathLike);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;QACjC,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,iBAAiB;YACvB,MAAM,EAAE,KAAK;SACd,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC;QACvC,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,IAAI;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,UAAU,GAAG,OAAO;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;IAE9C,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const severityRank = {
|
|
2
|
+
unknown: 0,
|
|
3
|
+
low: 1,
|
|
4
|
+
medium: 2,
|
|
5
|
+
high: 3
|
|
6
|
+
};
|
|
7
|
+
export function highestSeverity(values) {
|
|
8
|
+
if (values.length === 0) {
|
|
9
|
+
return "low";
|
|
10
|
+
}
|
|
11
|
+
return values.reduce((highest, current) => severityRank[current] > severityRank[highest] ? current : highest);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=severity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"severity.js","sourceRoot":"","sources":["../../src/utils/severity.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAA6B;IAC7C,OAAO,EAAE,CAAC;IACV,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;CACR,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,MAAkB;IAChD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CACxC,YAAY,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAClE,CAAC;AACJ,CAAC"}
|
package/docs/fixtures.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Fixture Contributions
|
|
2
|
+
|
|
3
|
+
Fixtures are how Glamsterdam Compatibility Lab learns which scanner signals are useful. Prefer small, reviewable examples that exercise one behavior clearly.
|
|
4
|
+
|
|
5
|
+
## What to Share
|
|
6
|
+
|
|
7
|
+
- EVM runtime bytecode or init code with enough context to know which one it is.
|
|
8
|
+
- Transaction traces from tools such as geth `debug_traceTransaction`, Besu, Nethermind, Foundry, Hardhat, Erigon, or call tracers.
|
|
9
|
+
- Indexer and explorer configs, including subgraphs, event/call/block handlers, and replay settings.
|
|
10
|
+
- Validator or operator configs with client, builder/API, monitoring, and testnet/devnet metadata.
|
|
11
|
+
- Compatibility matrices that are explicitly sourced from client release notes, devnet docs, or maintainer statements.
|
|
12
|
+
|
|
13
|
+
## Redaction Rules
|
|
14
|
+
|
|
15
|
+
Remove private keys, seed phrases, auth tokens, RPC credentials, validator keys, fee recipient secrets, internal hostnames, private endpoints, and non-public incident details.
|
|
16
|
+
|
|
17
|
+
For public-chain examples, addresses and transaction hashes are usually fine if they are already public. For private or internal examples, replace addresses, hashes, hostnames, and organization names with deterministic placeholders.
|
|
18
|
+
|
|
19
|
+
## Minimum Metadata
|
|
20
|
+
|
|
21
|
+
When possible, include:
|
|
22
|
+
|
|
23
|
+
- Source type: synthetic, public-chain, public repo, anonymized internal, or generated example.
|
|
24
|
+
- Tool or client name and version.
|
|
25
|
+
- Command or API used to produce the fixture.
|
|
26
|
+
- Trace mode or tracer name, such as `structLogs` or `callTracer`.
|
|
27
|
+
- Network, chain ID, or devnet name.
|
|
28
|
+
- Whether the fixture is complete or intentionally partial.
|
|
29
|
+
- Expected scanner behavior, including findings that should or should not appear.
|
|
30
|
+
|
|
31
|
+
## Licensing
|
|
32
|
+
|
|
33
|
+
Only contribute fixtures that can be published under this repository's license. If a fixture came from another project, include the source URL and license. When in doubt, open a fixture contribution issue before opening a pull request.
|
|
34
|
+
|
|
35
|
+
## Snapshot Expectations
|
|
36
|
+
|
|
37
|
+
If a fixture changes report wording or JSON structure, update golden report snapshots with:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
pnpm test:update
|
|
41
|
+
pnpm test
|
|
42
|
+
pnpm build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Snapshots are part of the product. They protect report language from accidental drift.
|
|
46
|
+
|
|
47
|
+
## Capturing RPC Traces
|
|
48
|
+
|
|
49
|
+
Use `scan-tx --trace-out` when you have an execution RPC endpoint that supports `debug_traceTransaction`:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
ETH_RPC_URL=https://your-execution-rpc.example \
|
|
53
|
+
pnpm glamsterdam scan-tx \
|
|
54
|
+
--tx 0x0000000000000000000000000000000000000000000000000000000000000000 \
|
|
55
|
+
--trace-out fixtures/traces/example-real-trace.json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Review the saved file before committing it. Remove credentials, internal hostnames, private transaction data, and anything that is not safe to publish.
|
|
59
|
+
|
|
60
|
+
`fixtures/traces/drpc-call-tracer-real.json` is an example of this flow. It was captured from a public Ethereum transaction using a public dRPC endpoint with `--tracer callTracer`; the fixture is public-chain data and should be treated as a normalization sample, not as an endorsement of any RPC provider.
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Release Runbook
|
|
2
|
+
|
|
3
|
+
This project publishes GitHub releases and npm packages separately. A release is not complete until both the GitHub release exists and npm shows the expected package version.
|
|
4
|
+
|
|
5
|
+
## Current npm target
|
|
6
|
+
|
|
7
|
+
- Package: `glamsterdam-compat-lab`
|
|
8
|
+
- Current release tag: `v0.2.2`
|
|
9
|
+
- Expected npm version: `0.2.2`
|
|
10
|
+
- Publish workflow: `.github/workflows/npm-publish.yml`
|
|
11
|
+
|
|
12
|
+
## Preflight
|
|
13
|
+
|
|
14
|
+
Run these checks before publishing:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
pnpm test
|
|
18
|
+
pnpm build
|
|
19
|
+
pnpm pack:dry-run
|
|
20
|
+
pnpm release:check-pack
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`pnpm release:check-pack` packs the current build, installs the tarball into a temporary global prefix, verifies the `glamsterdam` bin, and confirms the real public trace fixture is included.
|
|
24
|
+
|
|
25
|
+
Confirm the package is not already published at the target version:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm view glamsterdam-compat-lab version --json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
You can also run the release readiness helper, which checks the npm registry, local npm login state, local `NPM_TOKEN` or `NODE_AUTH_TOKEN` environment presence, GitHub `NPM_TOKEN` secret presence, and the publish workflow's OIDC shape:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
pnpm release:check-npm
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Preferred path: npm Trusted Publishing
|
|
38
|
+
|
|
39
|
+
npm Trusted Publishing uses GitHub Actions OIDC instead of a long-lived npm token. The `Publish npm` workflow is configured for this path with a GitHub-hosted runner, Node 24, `id-token: write`, `actions/setup-node` registry setup for `https://registry.npmjs.org`, and `npm publish --provenance`.
|
|
40
|
+
|
|
41
|
+
The default OIDC path does not require an npm token secret. If `NPM_TOKEN` is present, the workflow writes a temporary `.npmrc` only for that token fallback.
|
|
42
|
+
|
|
43
|
+
Configure npm with:
|
|
44
|
+
|
|
45
|
+
- Provider: GitHub Actions
|
|
46
|
+
- Owner or organization: `CruzMolina`
|
|
47
|
+
- Repository: `glamsterdam-compat-lab`
|
|
48
|
+
- Workflow file: `npm-publish.yml`
|
|
49
|
+
- Environment: `npm-publish`
|
|
50
|
+
|
|
51
|
+
The workflow uses the GitHub Environment `npm-publish`, which is restricted to protected branches. If you require manual approval or environment-scoped secrets for publishing, configure them on that environment.
|
|
52
|
+
|
|
53
|
+
If your local npm session has package write access, the equivalent CLI setup is:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
npx --yes npm@11.14.0 trust github glamsterdam-compat-lab \
|
|
57
|
+
--repo CruzMolina/glamsterdam-compat-lab \
|
|
58
|
+
--file npm-publish.yml \
|
|
59
|
+
--env npm-publish
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
npm documents `npm trust` as the command-line equivalent of managing trusted publisher configurations on npmjs.com. It requires npm 11.10.0 or newer, an npm owner or publisher login, write permission on the package, and 2FA when the account requires it. If the command fails with `E401` and says you must be logged in to publish packages, authenticate with the npm owner or publisher account before retrying. For a first publish of this unscoped package, use an npm owner or publisher session to try the CLI or npmjs.com setup. If npm does not allow the trusted publisher to be configured before the first publish, use the `NPM_TOKEN` fallback below for the first publish and switch back to Trusted Publishing afterward.
|
|
63
|
+
|
|
64
|
+
Trusted Publishing also validates repository metadata during publish. Keep `package.json` `repository.url` aligned with `git+https://github.com/CruzMolina/glamsterdam-compat-lab.git`.
|
|
65
|
+
|
|
66
|
+
You can verify the trusted-publisher shape without writing to npm:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
npx --yes npm@11.14.0 trust github glamsterdam-compat-lab \
|
|
70
|
+
--repo CruzMolina/glamsterdam-compat-lab \
|
|
71
|
+
--file npm-publish.yml \
|
|
72
|
+
--env npm-publish \
|
|
73
|
+
--dry-run --json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then run the workflow from `main`:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
gh workflow run npm-publish.yml \
|
|
80
|
+
--ref main \
|
|
81
|
+
-f release_tag=v0.2.2 \
|
|
82
|
+
-f dry_run=true \
|
|
83
|
+
-f tag=latest
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If the dry run passes, run the real publish:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
gh workflow run npm-publish.yml \
|
|
90
|
+
--ref main \
|
|
91
|
+
-f release_tag=v0.2.2 \
|
|
92
|
+
-f dry_run=false \
|
|
93
|
+
-f tag=latest
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
If the real publish fails with `ENEEDAUTH`, verify the npm Trusted Publishing configuration first. The workflow filename and repository fields are case-sensitive.
|
|
97
|
+
|
|
98
|
+
If the logs show `Signed provenance statement` followed by `npm error 404 Not Found - PUT`, OIDC/provenance is working, but npm has not authorized this workflow or account to publish the package name. Verify the Trusted Publishing package grant. If npm does not allow Trusted Publishing to be configured before the first publish of this unscoped package, use the token fallback below for the first publish, then switch the package to Trusted Publishing afterward.
|
|
99
|
+
|
|
100
|
+
## Fallback path: npm token
|
|
101
|
+
|
|
102
|
+
Create a granular npm access token with read/write package permission for `glamsterdam-compat-lab` or all packages the npm owner can publish. If the npm account or package requires 2FA, enable the token's bypass-2FA option for non-interactive CI publishing. Then add the token as the `NPM_TOKEN` secret on the `npm-publish` environment or as a repository secret.
|
|
103
|
+
|
|
104
|
+
If the token is available in your shell as `NPM_TOKEN` or `NODE_AUTH_TOKEN`, set the environment secret without printing the token value:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
NPM_TOKEN="${NPM_TOKEN:-${NODE_AUTH_TOKEN:-}}"
|
|
108
|
+
test -n "${NPM_TOKEN:-}" || { echo "Set NPM_TOKEN or NODE_AUTH_TOKEN first"; exit 1; }
|
|
109
|
+
gh secret set NPM_TOKEN --repo CruzMolina/glamsterdam-compat-lab --env npm-publish --body "$NPM_TOKEN"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
When this secret is present, the workflow exports it as `NODE_AUTH_TOKEN` and writes a temporary npm user config for the publish step. When the secret is absent, the workflow leaves token auth unset and relies on Trusted Publishing/OIDC.
|
|
113
|
+
|
|
114
|
+
Rerun the same workflow:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
gh workflow run npm-publish.yml \
|
|
118
|
+
--ref main \
|
|
119
|
+
-f release_tag=v0.2.2 \
|
|
120
|
+
-f dry_run=false \
|
|
121
|
+
-f tag=latest
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
After a successful token-based publish, configure Trusted Publishing for future releases and revoke unused publish tokens.
|
|
125
|
+
|
|
126
|
+
## Done criteria
|
|
127
|
+
|
|
128
|
+
The npm release is done when all of these are true:
|
|
129
|
+
|
|
130
|
+
- The `Publish npm` workflow completed successfully for `release_tag=v0.2.2`.
|
|
131
|
+
- `npm view glamsterdam-compat-lab version --json` returns `"0.2.2"`.
|
|
132
|
+
- Issue #17 is closed with the successful workflow run link.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Example: storage-heavy bytecode report
|
|
2
|
+
|
|
3
|
+
Command:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
pnpm glamsterdam scan-bytecode fixtures/bytecode/storage-heavy.hex --format markdown
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Output excerpt:
|
|
10
|
+
|
|
11
|
+
```md
|
|
12
|
+
# Glamsterdam Compatibility Report
|
|
13
|
+
|
|
14
|
+
Target: bytecode fixtures/bytecode/storage-heavy.hex
|
|
15
|
+
Tool version: 0.1.0
|
|
16
|
+
Fork registry: glamsterdam
|
|
17
|
+
|
|
18
|
+
## Summary
|
|
19
|
+
|
|
20
|
+
Overall risk: MEDIUM
|
|
21
|
+
Findings: 6 total, 0 high, 3 medium, 2 low, 1 unknown
|
|
22
|
+
|
|
23
|
+
## Findings
|
|
24
|
+
|
|
25
|
+
### 1. State and account access opcodes are prominent in bytecode
|
|
26
|
+
|
|
27
|
+
Severity: MEDIUM
|
|
28
|
+
Confidence: medium
|
|
29
|
+
Domains: contracts, execution
|
|
30
|
+
Related EIPs: GAS-REPRICING, EIP-7904, EIP-8038, EIP-7976
|
|
31
|
+
|
|
32
|
+
This bytecode contains multiple storage, account, or hashing opcodes. Glamsterdam gas repricing candidates may change the cost profile of state-heavy execution, but static bytecode does not prove those paths are hot.
|
|
33
|
+
|
|
34
|
+
Recommendation: Replay representative transactions and benchmark hot paths once a Glamsterdam client/devnet or local fork configuration is available.
|
|
35
|
+
|
|
36
|
+
### 3. Contract creation opcodes are present
|
|
37
|
+
|
|
38
|
+
Severity: MEDIUM
|
|
39
|
+
Confidence: high
|
|
40
|
+
Domains: contracts, execution
|
|
41
|
+
Related EIPs: GAS-REPRICING, EIP-8037
|
|
42
|
+
|
|
43
|
+
CREATE or CREATE2 appears in the bytecode. State-creation repricing candidates may affect factory, clone, deployment, or account-creation-heavy paths depending on final Glamsterdam scope.
|
|
44
|
+
|
|
45
|
+
Recommendation: Identify representative deployment/factory transactions and add them to fork-readiness replay tests.
|
|
46
|
+
|
|
47
|
+
### 6. Manual review is still required for runtime behavior
|
|
48
|
+
|
|
49
|
+
Severity: UNKNOWN
|
|
50
|
+
Confidence: low
|
|
51
|
+
Domains: contracts, execution
|
|
52
|
+
Related EIPs: GAS-REPRICING
|
|
53
|
+
|
|
54
|
+
The scanner found static opcode evidence, but exact fork impact depends on executed paths, calldata, storage warmness, account state, compiler output, and final Glamsterdam parameters.
|
|
55
|
+
|
|
56
|
+
Recommendation: Use this report to choose transactions for trace replay and benchmark them under current and Glamsterdam configurations.
|
|
57
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0x600054600055600154600155600254600255600354600355600454600455600060006000f06000600060006000f5313b3f3760006000a100
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "balance-diff-indexer",
|
|
3
|
+
"pipeline": {
|
|
4
|
+
"nativeEthTransfers": {
|
|
5
|
+
"source": "balanceDiff",
|
|
6
|
+
"description": "Synthetic fixture that models native ETH transfer handling through balance diff logic."
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"compatibility": {
|
|
10
|
+
"glamsterdam": {
|
|
11
|
+
"reviewedEips": ["EIP-7708"],
|
|
12
|
+
"replayPlan": "Run replay against a Glamsterdam devnet when available."
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
specVersion: 1.0.0
|
|
2
|
+
schema:
|
|
3
|
+
file: ./schema.graphql
|
|
4
|
+
dataSources:
|
|
5
|
+
- kind: ethereum/contract
|
|
6
|
+
name: ExampleToken
|
|
7
|
+
network: mainnet
|
|
8
|
+
source:
|
|
9
|
+
address: "0x0000000000000000000000000000000000000000"
|
|
10
|
+
abi: ExampleToken
|
|
11
|
+
startBlock: 1
|
|
12
|
+
mapping:
|
|
13
|
+
kind: ethereum/events
|
|
14
|
+
apiVersion: 0.0.9
|
|
15
|
+
language: wasm/assemblyscript
|
|
16
|
+
entities:
|
|
17
|
+
- Transfer
|
|
18
|
+
abis:
|
|
19
|
+
- name: ExampleToken
|
|
20
|
+
file: ./abis/ExampleToken.json
|
|
21
|
+
eventHandlers:
|
|
22
|
+
- event: Transfer(indexed address,indexed address,uint256)
|
|
23
|
+
handler: handleTransfer
|
|
24
|
+
file: ./src/example-token.ts
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": "besu-debug-structlogs-fixture-v0",
|
|
3
|
+
"source": "Synthetic fixture shaped like a Besu debug_traceTransaction structLogs response.",
|
|
4
|
+
"jsonrpc": "2.0",
|
|
5
|
+
"id": 1,
|
|
6
|
+
"result": {
|
|
7
|
+
"gas": "0x33450",
|
|
8
|
+
"failed": false,
|
|
9
|
+
"returnValue": "0x",
|
|
10
|
+
"structLogs": [
|
|
11
|
+
{ "pc": 0, "op": "PUSH1", "depth": 1, "gas": 210000, "gasCost": 3 },
|
|
12
|
+
{ "pc": 2, "op": "SLOAD", "depth": 1, "gas": 209997, "gasCost": 100 },
|
|
13
|
+
{ "pc": 3, "op": "SSTORE", "depth": 1, "gas": 209897, "gasCost": 2900 },
|
|
14
|
+
{ "pc": 4, "op": "CALL", "depth": 2, "gas": 206997, "gasCost": 700, "calldataBytes": 256 },
|
|
15
|
+
{ "pc": 5, "op": "LOG1", "depth": 1, "gas": 206297, "gasCost": 375 }
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "CALL",
|
|
3
|
+
"from": "0x0000000000000000000000000000000000000001",
|
|
4
|
+
"to": "0x0000000000000000000000000000000000000002",
|
|
5
|
+
"input": "0x12345678",
|
|
6
|
+
"logs": [{}],
|
|
7
|
+
"calls": [
|
|
8
|
+
{
|
|
9
|
+
"type": "CREATE2",
|
|
10
|
+
"from": "0x0000000000000000000000000000000000000002",
|
|
11
|
+
"input": "0x60006000"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "CALL",
|
|
15
|
+
"from": "0x0000000000000000000000000000000000000002",
|
|
16
|
+
"to": "0x0000000000000000000000000000000000000003",
|
|
17
|
+
"input": "0xabcdef",
|
|
18
|
+
"calls": [
|
|
19
|
+
{
|
|
20
|
+
"type": "STATICCALL",
|
|
21
|
+
"to": "0x0000000000000000000000000000000000000004",
|
|
22
|
+
"input": "0x01"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|