Counting functions in bytecode
A rough estimate of how many functions an unverified contract exposes, and why it is only a lead.
#Plain languageIn plain terms
When a contract has not published its source, you still want a sense of its size. Is it a simple token with a handful of functions, or something with a hundred entry points?
Forensia gives a rough count by looking for a pattern in the machine code that usually marks a function. It is a quick estimate to guide the next step. It is not a list of functions and it can be wrong in both directions.
#How it worksHow it works
Compiled contracts start with a dispatcher. It compares the first four bytes of an incoming call against each function's four-byte identifier, called a selector. To do that, the code pushes each selector onto the stack using an instruction named PUSH4. Counting PUSH4 instructions with distinct values approximates the number of functions.
#Technical detailThe exact rules
The whole method is one pattern match over the code as hex text.
lowercase(code)
match every 63[0-9a-f]{8} // 0x63 is PUSH4, then four bytes
count the distinct matchesOnly the count is kept. The matched values are not stored and are not looked up in a signature database. The result is the finding finding:selector-surface, class lead, confidence low. The same count is taken for a resolved proxy implementation and kept in the proxy record.
#LimitsWhat it does not tell you
- There is no disassembly. The match does not know where instructions start, so the byte
63inside another instruction's data still counts. - The match runs over hex characters, not whole bytes, so a
63formed by the second half of one byte and the first half of the next also counts. - The compiler's metadata trailer is not removed before matching.
- Constants that are not selectors, such as
0xffffffff, are not filtered out. - For real function names, rely on verified source metadata. This count is for contracts that have none.