Sovryn-smart-contracts icon indicating copy to clipboard operation
Sovryn-smart-contracts copied to clipboard

Script to create report on bytecodes not supported by zkSync

Open tjcloa opened this issue 4 years ago • 7 comments

Report on all our contracts in the sovryn-solidity-contracts and oracle-based-amm repos the number of occurence of every opcode (ADDMOD, SMOD, MULMOD, EXP, and CREATE2, SELFDESTRUCT) by contracts contract | ADDMOD | MULMOD | EXP | CREATE2 | SELFDESTRUCT LoanToken | 1 | 3 | 5 | 2 | 0

tjcloa avatar Jun 23 '21 12:06 tjcloa

Reporting results at: https://docs.google.com/spreadsheets/d/1qgpTpM2pXKF4QaJnTFzsupv839judvlJJ3xlp22lUEg/edit?usp=sharing

computerphysicslab avatar Jun 23 '21 12:06 computerphysicslab

The script now automatically creates a CSV result file exported to Google Docs at:

https://docs.google.com/spreadsheets/d/1SPeqBk7vRxKlSlvDqKycSRsxFjEGRUj9O-XMr-YMG_8/edit?usp=sharing

computerphysicslab avatar Jun 25 '21 08:06 computerphysicslab

Script completed:

SOVRYN TOTAL FREQUENCIES: EXP: 242 ADDMOD: 4 SMOD: 12 MULMOD: 3 CREATE2: 10 SELFDESTRUCT: 6

AMM TOTAL FREQUENCIES: EXP: 3716 ADDMOD: 3 SMOD: 7 MULMOD: 7 CREATE2: 1 SELFDESTRUCT: 4

In-detail results => https://docs.google.com/spreadsheets/d/1SPeqBk7vRxKlSlvDqKycSRsxFjEGRUj9O-XMr-YMG_8/edit?usp=sharing

computerphysicslab avatar Jun 25 '21 11:06 computerphysicslab

Hardhat compilation output gives 2 opcode sets for every contract: "bytecode" and "deployedBytecode"

The script is using "bytecode" because it uses to be a bit larger than "deployedBytecode"

computerphysicslab avatar Jun 25 '21 11:06 computerphysicslab

The compiler can also generate a mapping from the bytecode to the range in the source code that generated the instruction.

https://docs.soliditylang.org/en/v0.7.5/internals/source_mappings.html

https://ethereum.stackexchange.com/questions/25479/how-to-map-evm-trace-to-contract-source

Next step is using this extra information from the compiler called "source mappings" to locate with better accuracy the conflicting opcodes inside their contracts. The idea is to get a list of contracts to review for zkSync adoption, this is done, but besides to find a range in the source code that generated the incompatible instruction.

I am researching this source map, and it needs first to be decoded, because the source map format is compressed and provides just the byte offsets in the source files, not line and column numbers. So additionally a parse of the source files is needed, creating a mapping from byte offset to line/column pairs.

So it is a lot of work ahead to achieve this improvement, but I think it can be done.

computerphysicslab avatar Jun 29 '21 11:06 computerphysicslab

Looked for libraries or external Python implementations of the sourcemap decoder, but no luck:

https://github.com/search?l=Python&q=sourcemap&type=Repositories

https://github.com/search?l=Python&q=solidity&type=Repositories

computerphysicslab avatar Jun 30 '21 12:06 computerphysicslab

By using jsfiddle to track decoder values line by line: https://jsfiddle.net/73s6mjdn/

srcmap = "24:101:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24:101:0;;;;;;;";
const parsed = srcmap
.split(";")
    ["24:101:0:-", "", "", "", "8:9:-1", "5:2", "", "", "30:1", "27", "20:12", "5:2", "24:101:0", "", "", "", "", "", "", ""]

.map(l => l.split(":"))
    [["24", "101", "0", "-"], [""], [""], [""], ["8", "9", "-1"], ["5", "2"], [""], [""], ["30", "1"], ["27"], ["20", "12"], ["5", "2"], ["24", "101", "0"], [""], [""], [""], [""], [""], [""], [""]]

.map(([s, l, f, j]) => ({ s: s === "" ? undefined : s, l, f, j }))
    [  [object Object] { f: "0", j: "-", l: "101", s: "24"
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: "-1", j: undefined, l: "9", s: "8"
    }, [object Object] { f: undefined, j: undefined, l: "2", s: "5"
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: "1", s: "30"
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: "27"
    }, [object Object] { f: undefined, j: undefined, l: "12", s: "20"
    }, [object Object] { f: undefined, j: undefined, l: "2", s: "5"
    }, [object Object] { f: "0", j: undefined, l: "101", s: "24"
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }, [object Object] { f: undefined, j: undefined, l: undefined, s: undefined
    }]

.reduce...
    [  [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: -1, j: "-", l: 2, s: 5
    }, [object Object] { f: -1, j: "-", l: 12, s: 20
    }, [object Object] { f: -1, j: "-", l: 1, s: 27
    }, [object Object] { f: -1, j: "-", l: 1, s: 30
    }, [object Object] { f: -1, j: "-", l: 2, s: 5
    }, [object Object] { f: -1, j: "-", l: 2, s: 5
    }, [object Object] { f: -1, j: "-", l: 2, s: 5
    }, [object Object] { f: -1, j: "-", l: 9, s: 8
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { f: 0, j: "-", l: 101, s: 24
    }, [object Object] { ... }]

It is confirmed that the js code extracts 20 references for an opcode set of near 100 instructions.

So, we cannot expect to get a complete and meaningful mapping(opcode instruction => code reference) by using sourcemap.

computerphysicslab avatar Jul 01 '21 11:07 computerphysicslab