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

Implement partial transpilation #130

Merged
merged 33 commits into from
Sep 25, 2023

Conversation

Amxx
Copy link
Contributor

@Amxx Amxx commented Sep 19, 2023

No description provided.

@Amxx Amxx requested a review from frangio September 19, 2023 13:52
throw new Error(`Can't find symbol imported in ${ast.absolutePath}`);
declare module '../transform' {
interface TransformData {
importPath: string;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm open to a better name for this.

Meaning is:

  • for nodes that are contract definition (includes libraries and interfaces)
    • should the node not be transpiled
    • if so, where should it be imported from.

said otherwize:

  • undefined means object should be transpiled as expected (no particular treadment)
  • string means the object should not be transpiled
    • code should be removed
    • imports in other files should like to this importPath
    • reference to this object should not be renamed

I'm also wondering if this is the right location to declare that field.

Copy link
Contributor

@frangio frangio Sep 21, 2023

Choose a reason for hiding this comment

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

Could be importFromPeer?: string.

Note that it should be defined as an optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • In fix-new-statement.ts, isUsedInNewStatement is not optional
  • getData has type (node: Node) => Partial<TransformData>;

So why would it be marked optional here ?

src/cli.ts Outdated Show resolved Hide resolved
src/transform.ts Outdated Show resolved Hide resolved
src/index.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

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

Looks pretty good but I left some important comments below.

One thing that I see in the spec and not addressed here is throwing an error if an excluded definition contains a reference to a transpiled definition. Is that something we want to do? I think one example of this would be: suppose SafeERC20 had references to ERC20 instead of IERC20. Should that be a transpiler error? Now that I think about it it doesn't sound like that would be a problem in any way.

src/transformations/fix-import-directives.ts Outdated Show resolved Hide resolved
src/index.ts Outdated Show resolved Hide resolved
src/index.ts Outdated
Comment on lines 87 to 88
for (const node of findAll('ContractDefinition', ast)) {
if (node.contractKind === 'contract') {
Copy link
Contributor

Choose a reason for hiding this comment

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

In our spec we had written that we'd also exclude "contracts with @custom:need-not-transpile".

Do we want to do this? Do we need it for OZ Contracts?

If we do it, we will need a new helper similar to extractContractStorageSize in utils/natspec.ts.

Copy link
Contributor Author

@Amxx Amxx Sep 25, 2023

Choose a reason for hiding this comment

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

Do we need it for OZ Contracts?

Not really. Maybe that could replace some of the "initializable" specific logic, but its not something we absolutelly need.
If we do so, do we also add a @custom:force-transpile tag that does the opposit ?

Copy link
Contributor

Choose a reason for hiding this comment

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

@custom:force-transpile is not what we need, I can't imagine a use case for it. I think the only contract where need-not-transpile could be relevant is UUPSUpgradeable. The current logic transpiles UUPSUpgradeable, though for this contract in particular we have a trick which is that we don't add the *Upgradeable suffix because the identifier already has it. Since it doesn't have any storage variables it won't get a namespace either. It does have initializers added.

Perhaps it's best to keep transpiling this contract and others simply for consistency, the initializers might be enough of a reason.

Copy link
Contributor Author

@Amxx Amxx Sep 25, 2023

Choose a reason for hiding this comment

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

Should "@Custom:need-not-transpile" apply to contracts or also to other objects (free function, structure definition, ...)

In the context of "peerImport", they would automatically be skiped, but we could imagine a project without "peerImport", where everything is transpiled by default, except for some @custom:need-not-transpile objects.

Also, what if they are used anywhere, and we don't have a peerImport path for them? How should we deal with that? Throw an error?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, what if they are used anywhere, and we don't have a peerImport path for them? How should we deal with that? Throw an error?

Yeah that's a good question.

If we don't need this for OZ Contracts, let's not do it.

src/transformations/remove-partial.ts Outdated Show resolved Hide resolved
src/transform.ts Outdated Show resolved Hide resolved
@Amxx
Copy link
Contributor Author

Amxx commented Sep 25, 2023

In the current implementation, if a peerProject is set:

  • contracts are transpiled
  • anything else, declared at the file level, is NOT transpiled. This includes :
    • interfaces: I think these should not be transpiled
    • libraries: This should not be transpiled, except maybe functions that take contract (that are transpiled) as arguments.
    • custom errors: I think these should not be transpiled
    • free functions: Same as functions in libraries. We only need to transpile them if they take arguments that are contract.
    • UDVT: I think these should not be transpiled
    • structs: Same as libraries and free function. It may contain references to contracts that are transpiled.

Are these assumptions reasonables?

  • Functions in libraries don't have contract arguments, and use interfaces instead.
  • Free functions don't have contract arguments, and use interfaces instead.
  • Both of the above do not call functions that take contract arguments
    • I tink this is ok, because in order to call such functions, they would either need to get these as arguments, or do a casting.

If the assumptions are ok, do we want to check them?

@frangio
Copy link
Contributor

frangio commented Sep 25, 2023

Are these assumptions reasonables?

I think they are reasonable, but moreover if they are broken I don't think it would cause any correctness/security issues, only usability issues. If you agree with that, I don't think we need to validate the assumptions.

Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

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

LGTM!

@Amxx Amxx merged commit a0190f7 into OpenZeppelin:master Sep 25, 2023
2 checks passed
@Amxx Amxx deleted the feature/partialTranspilation branch September 25, 2023 15:15
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.

2 participants