Skip to content
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

Solidity binding fixes driven by Sanctuary #1149

Merged
merged 69 commits into from
Dec 14, 2024

Conversation

ggiraldez
Copy link
Contributor

@ggiraldez ggiraldez commented Nov 15, 2024

This PR contains fixes to bindings for issues that were found by trying to resolve all references in Sanctuary, as well as test cases to verify them. It also improves documentation of the rules and improvements (renames and rearrangements) for readability. The built-in types are also standardized with a PascalCase naming convention.

Most notably, it introduces extension scopes to support resolving attached function set via using directives. These extension scopes need to be accessible at any point during the resolution of a symbol stack if the originating reference is located in a lexical scope which is affected by a using directive. This forced a refactor of the lexical scope node structure, introducing a new .extended_scope available in nodes where references may need to resolve to attached functions (ie. function bodies, constant initialization expressions, etc.) Also, for Solidity < 0.7.0 using directives are inherited, so we need to propagate the new extension scopes for all sub-contracts relative to where the directive is located.

The extension scope mechanism is implemented using the jump to scope and scope stack features of the stack graphs. The extended scope would optionally push the extension scope for the current contract and then continue resolution through the normal lexical scope. This effectively doubles the search space in the graph when performing a resolution, and this happens every time we inject a new extension scope to the scope stack. This has the potential to exponentially increase the running times and memory requirements. This is a known caveat which will be addressed in a future PR.

- `string` and `bytes` are exported as built-in variables resolving to types
that provide a `concat` function
- `address` can be used as a function to cast a parameter to `address` to eg.
retrieve the balance
This makes resolving to attached functions on types even when the reference of
those types happen in a different lexical scope.
And also provide alternative paths with and without propagating the dynamic
scope. Otherwise, since scope accumulate on the stack it's possible we'll need
to resolve an attached function with the wrong dynamic scope at the top of the
scope stack.
Both contracts and libraries can optionally push the dynamics scope when
traversing to the parent lexical scope (ie. the source unit). But for libraries,
they can also optionally push their name to correctly bind internal types which
were extended (with `using`) by their qualified name (ie. `Lib.Type`).
Applying a function call with a type will always return a value of that type, so
a symbol stack `type,()` is equivalent to `type,@typeof`. Reflect on the binding
entry point of the using clause.
These are parsed as modifiers, and they need a similar treatment as parent
constructor calls in new constructor definitions.
@ggiraldez ggiraldez marked this pull request as ready for review November 22, 2024 18:57
ggiraldez added a commit to manastech/slang that referenced this pull request Nov 25, 2024
This happens when there is special member access in some Yul identifier (like
`x.slot` or `x.offset`). I think this issue was introduced when unreserving the
`address` keyword since that changed the structure of `YulPath`. There is a
proper test case in NomicFoundation#1149 already, but without this fix running Sanctuary with
existing rules crashes.
@ggiraldez ggiraldez force-pushed the sanctuary-fixes-only branch from 40e6da0 to 4c19da0 Compare November 26, 2024 23:54
Copy link
Contributor

@OmarTawfik OmarTawfik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
For the unresolved comments, I'm happy to follow up on it later.

github-merge-queue bot pushed a commit that referenced this pull request Nov 28, 2024
This PR adds a step to Sanctuary testing to exercise bindings. We now
also consider a Sanctuary test to fail if any of the references found in
it cannot be resolved to one (or possibly more) definitions.

This also includes a small binding rules fix to avoid crashing if we
find a Solidity source file with an assembly block that has a `YulPath`
with more than one identifier (eg. a member access like `x.slot`). This
is properly tested in #1149, but without it running Sanctuary tests will
crash since there are contracts with the aforementioned contents.
github-merge-queue bot pushed a commit that referenced this pull request Dec 2, 2024
I found this additional required fix after merging #1159. This is so
bindings can be processed for files with using directives on mapping
types without crashing. We want to merge this before #1149 to get a
meaningful baseline before those fixes are applied.
@ggiraldez ggiraldez added this pull request to the merge queue Dec 14, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Dec 14, 2024
@ggiraldez ggiraldez added this pull request to the merge queue Dec 14, 2024
Merged via the queue into NomicFoundation:main with commit 2ffc8f5 Dec 14, 2024
1 check passed
@ggiraldez ggiraldez deleted the sanctuary-fixes-only branch December 14, 2024 00:43
github-merge-queue bot pushed a commit that referenced this pull request Dec 17, 2024
This PR builds on top of #1149

This changes the way we handle extension scopes (ie. `using` directives)
in bindings. Instead of using the scope stack from the stack graph, we
hook into the resolution algorithm and inject new graph edges from nodes
designated as extension hooks (usually the source unit's lexical scope)
to extension scopes which are defined at each contract/library and
contain the definition nodes from `using` directives. This simplifies
the rules quite a bit and greatly improves performance, particularly in
the case of Solidity < 0.7.0 where `using` directives are inherited from
base contracts.

This PR also moves built-ins parsing and ingestion to `slang_solidity`
crate. Since the built-ins file needs to be pre-processed to transform
the symbols as to ensure no conflicts can occur with user code, adding
the built-ins requires a couple of manual steps that were replicated in
every construction of Solidity bindings API. By encapsulating this
functionality in the `slang_solidity` crate we remove a source of user
error and make it easier to make changes to the built-ins ingestion
code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants