Sovryn-smart-contracts
Sovryn-smart-contracts copied to clipboard
Script to create report on bytecodes not supported by zkSync
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
Reporting results at: https://docs.google.com/spreadsheets/d/1qgpTpM2pXKF4QaJnTFzsupv839judvlJJ3xlp22lUEg/edit?usp=sharing
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
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
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"
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.
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
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.