-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: Improve flatten compilations to fail less on solc error[2333] and error [2449] #127
Comments
I've spent some more time debugging both of these occurences. Without the full detachment of associations<->filenames (topological sorting occurs on associations, but printing occuring as filenames) there are many edge cases that can exist. This is an issue inherant to flattening. Ive managed to piecemeal some more improvements to reduce the errors from occuring on ~30% of my contracts to about ~5%, but I dont believe there are worthy routes to fix the remainders. Having the directedAcyclicGraph load edges oppositely (target->source) allows the non-associated classes to be at the front of the sort after the reversing step, this helps majorly with declaration precedence. const loadDirectedAcyclicGraph = (umlClasses) => {
const directedAcyclicGraph = new js_graph_algorithms_1.DiGraph(umlClass_1.UmlClass.idCounter); // the number vertices in the graph
for (const sourceUmlClass of umlClasses) {
for (const association of Object.values(sourceUmlClass.associations)) {
// Find the first UML Class that matches the target class name
const targetUmlClass = (0, associations_1.findAssociatedClass)(association, sourceUmlClass, umlClasses);
if (!targetUmlClass || targetUmlClass.stereotype === 6 || targetUmlClass.stereotype === 5) { // stereotype 6 is contract-level-enum, 5 is contract-level-struct
continue;
}
// console.log(`Adding edge from ${sourceUmlClass.name} with id ${sourceUmlClass.id} to ${targetUmlClass.name} with id ${targetUmlClass.id} and type ${targetUmlClass.stereotype}`);
// directedAcyclicGraph.addEdge(sourceUmlClass.id, targetUmlClass.id);
directedAcyclicGraph.addEdge(targetUmlClass.id, sourceUmlClass.id);
}
}
// console.log(directedAcyclicGraph)
return directedAcyclicGraph;
}; |
And front loading all non-dependant nodes to the front of the list before a de-duping step helps to alleviate some edge cases where the graph is 'lazily sorted' (a minimal interface can be second to last if the last node is a contract that inherits from it). const topologicalSortClasses = (umlClasses) => {
const directedAcyclicGraph = loadDirectedAcyclicGraph(umlClasses);
const topologicalSort = new js_graph_algorithms_1.TopologicalSort(directedAcyclicGraph);
// Topological sort the class ids
// console.log(topologicalSort.order())
// const sortedUmlClassIds = topologicalSort.order().reverse();
let sortedUmlClassIds = topologicalSort.order();
// TODO need to make it so that nodes that are not included within the adjacency list are propelled to the top of the list
// seems like this list is lazily sorted. ex: a minimal interface can be second to last if the last node is a contract that inherits from it
// over range of 0..topologicalSort.V, push nodes into inclusion list
// for any number not in the inclusion list, push it to the front of the list
// console.log(topologicalSort)
// console.log(directedAcyclicGraph.V)
let not_included_nums = [];
const flattened_adj_list = directedAcyclicGraph.adjList.flat();
// console.log(flattened_adj_list)
for (let i=0; i < directedAcyclicGraph.V; i++) {
flattened_adj_list.includes(i) ? null : not_included_nums.push(i);
}
// console.log(not_included_nums.reverse()) // shouldn't need to reverse this, but seems like it preserves the order of the original list better
// console.log(sortedUmlClassIds)
sortedUmlClassIds = not_included_nums.concat(sortedUmlClassIds);
// console.log(sortedUmlClassIds)
sortedUmlClassIds = [...new Set(sortedUmlClassIds)]; // remove duplicates
// console.log(sortedUmlClassIds)
const sortedUmlClasses = sortedUmlClassIds.map((umlClassId) =>
// Lookup the UmlClass for each class id
umlClasses.find((umlClass) => umlClass.id === umlClassId
));
// Filter out any unfound classes. This happens when diff sources the second contract.
return sortedUmlClasses.filter((umlClass) => umlClass !== undefined);
}; |
I've been relying on flatten for some daily work auditing contracts, and I wanted to share a few errors I run into and a few workarounds Ive created to help get past them. Often times, both occur for similar reasons, but there are separate ways to fix these. I want to preface that I know absolutely 0 javascript, so please forgive the horrendous code workarounds...
Error 2449
This occurs due to one filename from etherscan containing multiple instances of contracts/interfaces/etc. For example, a minimalistic interface defined at the top of a file and a massively inheriting contract below it.
When the uml classes are topologically sorted, the minimal interface is at the front, and the massive contract at the back. This causes an error when umlclasses are mapped to their relative filenames, and then de-duplicated with a
Set()
. This causes the first instance to act as a hoist for the rest of the declared contracts in that file.The entire solidity code for the filename is concatenated for printout, and the massive file causes an error due to preceding definition.
The Fix
Still de-duplicate using a
Set()
, but do it in reverse order, so that the last instance of a filename in the sort is when the file gets printed. In other words, have the massive contract drag the minimal interfaces back.Can reproduce on this contract:
https://etherscan.io/address/0x91ee5184763d0b80f8dfdCbdE762b5D13ad295f4#code
sol2uml flatten 0x91ee5184763d0b80f8dfdCbdE762b5D13ad295f4
Error 2333
Etherscan allows multiple instances of the same contract/interface in the code list, so in this case it occurs due to
IERC20
repeating twice in the umlclasses list.It is quite annoying to remove... Here are my thoughts:
umlClass.operators
and checking for dupes onname
to be sufficientHere is my attempt at detecting supersets and modifying the topological sort:
Original ordering (notice the double occurence of IERC20):
New ordering:
Can reproduce on this contract:
https://etherscan.io/address/0x91ee5184763d0b80f8dfdCbdE762b5D13ad295f4#code
sol2uml flatten 0x91ee5184763d0b80f8dfdCbdE762b5D13ad295f4
The text was updated successfully, but these errors were encountered: