Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

feat(solc): yul compilation #994

Merged
merged 10 commits into from
Mar 10, 2022
Merged

Conversation

alexeuler
Copy link
Contributor

Motivation

Currently Foundry and ethers-rs is not capable of compiling Yul sources (foundry-rs/foundry#759)

Solution

Add yul compilation

@alexeuler alexeuler changed the title Feature/yul compilation feat(solc): yul compilation Mar 7, 2022
Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

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

Thanks!
this looks good!
only nit is the Vec<CompilerInput> return type

Source::read_all_from(path.as_ref()).map(Self::with_sources)
}

/// Creates a new Compiler input with default settings and the given sources
pub fn with_sources(sources: Sources) -> Self {
Self { language: "Solidity".to_string(), sources, settings: Default::default() }
pub fn with_sources(sources: Sources) -> Vec<Self> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since this returns at most vec![sol, yul]
can we add something like this perhaps

enum ProjectCompilerInput {
  Solidity(CompilerInput),
  Yul(..),
  Mixed(..,..)
}

?

Copy link
Contributor Author

@alexeuler alexeuler Mar 7, 2022

Choose a reason for hiding this comment

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

I think the CompilerInput abstraction is correct right now - i.e. it's the unit that get's fed into solc compiler. The with_sources method though doesn't work because if sources have different types that means that you'll have 2 compiler inputs the needs to be fed into solc sequentially. So to me the signature looks good. Plus the vec is extensible for other sources (if any :))

To be 100% clean we could update the new method so it's just a plain constructor taking language as an input. For that method it's really uncommon to return a Vec. I just left it as it is for now because it could be used in many places.

Wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

makes sense, however working with a Vec<CompilerInput> can be a bit annoying.
Should be fine for now, but I think we can make this more ergonomic with ProjectCompilerInput which requires some refactoring, which we should leave for a follow up.

Copy link
Owner

Choose a reason for hiding this comment

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

I am OK with this as-is, seems good enough for now!

@gakonst gakonst mentioned this pull request Mar 7, 2022
@ControlCplusControlV
Copy link

While this implementation is definitely more elegant than mine (#993) , given this approach of tying in Yul sources with Solidity sources for when I add Yul to foundry (which I am beginning after this, so lmk if you want to collab on it), but the one issue I can think of is with ABI, as Yul doesn't compile with an ABI by default, so adding some way to override the ABI of a Yul source would definitely be very helpful

@alexeuler
Copy link
Contributor Author

alexeuler commented Mar 7, 2022

While this implementation is definitely more elegant than mine (#993) , given this approach of tying in Yul sources with Solidity sources for when I add Yul to foundry (which I am beginning after this, so lmk if you want to collab on it), but the one issue I can think of is with ABI, as Yul doesn't compile with an ABI by default, so adding some way to override the ABI of a Yul source would definitely be very helpful

Yeah I was definitely thinking about adding abi for yul. My thinking was to load file with the same name as abi. E.g. if you have contracts/tokens/ERC20.yul then abi would be loaded from contracts/tokens/ERC20.abi.json. But that'd be a good next step.

In any case I'm ok to merge this one or yours or some combined version. The key is to have a mix of Solidity / Yul sources in one project which will be kinda cool since hardhat and other guys don't have it :)

@ControlCplusControlV
Copy link

ControlCplusControlV commented Mar 7, 2022

Yeah I was definitely thinking about adding abi for yul. My thinking was to load file with the same name as abi. E.g. if you have contracts/tokens/ERC20.yul then abi would be loaded from contracts/tokens/ERC20.abi.json. But that'd a good next step.
In any case I'm ok to merge this one or yours or some combined version. The key is to have a mix of Solidity / Yul sources in one project which will be kinda cool since hardhat and other guys don't have it :)

I can move over some of my changes here (mostly with the test) as suggestions and you can move them in as needed.

The mix is definitely really cool as only Truffle can do it. What would you think of an approach where we have a way to cast a Solidity interface over the Yul file (so yul_file_name.abi.sol) and compile the interface, and put the ABI on top of the Yul artifact, then those who want to skip it with call() have the option to, while others can use it like nothing is different

Edit : If so I can get that done relatively quickly as I've done this for my Yul+ toolchains before

@gakonst
Copy link
Owner

gakonst commented Mar 7, 2022

The mix is definitely really cool as only Truffle can do it. What would you think of an approach where we have a way to cast a Solidity interface over the Yul file (so yul_file_name.abi.sol) and compile the interface, and put the ABI on top of the Yul artifact, then those who want to skip it with call() have the option to, while others can use it like nothing is different

Supportive of this :)

I think let's coalesce the efforts around this PR for simplicity. @ControlCplusControlV can you make a PR against this one with any changes you have in mind?

@ControlCplusControlV
Copy link

@gakonst yeah will make that PR later today as I am going to add in that change to handle Yul ABI alongside with it.

@ControlCplusControlV
Copy link

My PR is up to @alexeuler's branch, still needs some work with one last type resolution issue which I can hopefully get resolved tomorrow as ABI should be fully functional from there!

@ControlCplusControlV
Copy link

So type issues is fixed, but need help with one last thing. In this part of my fork of artifact_output mod.rs I have both the abi I need to replace and the artifact of which I need to insert the ABI into. But it doesn't appear there is a clean way to do that as Artifact won't let me modify the ABI directly and if I convert it into a CompactContract I am running into issues converting it back, so was curious as to the best way to do this or any other approaches. Will continue testing things but wanted to ask here in case there is something I am missing which could speed things up

@mattsse
Copy link
Collaborator

mattsse commented Mar 9, 2022

I see, what modifications are necessary?
it seems like the proper way is to extend the Artifact trait some functions specifically for yul?

@ControlCplusControlV
Copy link

The ABI needs to be accessible so that it can be replaced for a given Artifact or ArtifactFile. I will try extending artifact although there is a lot of unwrapping needed to get to the ABI and with all the types that implement Artifact I was hoping there would be another way which requires less refactoring

@ControlCplusControlV
Copy link

@mattsse is there a specific way you envision extending Artifact ? As I need to replace the ABI but I haven't found a good way to access the ABI directly, as all the functions involve converting to a CompactContract to fetch values like ABI or Bytecode, but as there is no way to convert it back I haven't been able to get that approach to work. Is there a better way to directly access that value?

@mattsse
Copy link
Collaborator

mattsse commented Mar 9, 2022

@mattsse is there a specific way you envision extending Artifact ? As I need to replace the ABI but I haven't found a good way to access the ABI directly, as all the functions involve converting to a CompactContract to fetch values like ABI or Bytecode, but as there is no way to convert it back I haven't been able to get that approach to work. Is there a better way to directly access that value?

you mean the ethers::abi::Abi type? that type is baked into everything.
What kind of modification/conversion do need need?

I don't have the full picture yet, and would need some more context on what needs to be done here https://github.com/ControlCplusControlV/ethers-rs-1/blob/feature/yul_compilation/ethers-solc/src/artifact_output/mod.rs#L580

@ControlCplusControlV
Copy link

@mattsse I was actually able to resolve it by avoiding type conversions and just saving the Contract Object for each Yul contract, so that I could then just modify and replace it later. Just have one bug where it is compiling correctly but it seems the caching is overwriting the file contents instead of a cache, if you want to help I have pushed all my code to my fork and the test is fairly reliable producing it (It overwrites SimpleStore.yul with the cache of the artifact)

@ControlCplusControlV
Copy link

ControlCplusControlV commented Mar 10, 2022

@gakonst (and @alexeuler if you have availability to provide input) could you review my changes for ABI to start moving it upstream? PR is here and my fork is here. So sorry for how long this took, did realize how bad my rust type skills are (although they've improved much more now!). I've added tests but as I was iterating so much code style is a bit sloppy so if there are any code style choices I can gladly implement them.

It is a bit polluted with commits so squashing and merging will be much cleaner.

@mattsse
Copy link
Collaborator

mattsse commented Mar 10, 2022

great progress @ControlCplusControlV !
I looked at your PR but I'm not sure I can follow, I fail to make sense of the yul_abi_targets and all the conversions etc...

What'd be helpful is, if you could outline the motivation behind this with some additional details, especially how yul artifacts differ and why this is necessary?
otherwise this is a bit hard to review

@gakonst
Copy link
Owner

gakonst commented Mar 10, 2022

My candid recommendation would be that we merge this as-is, and @ControlCplusControlV can post a separate PR on top of master, given that it's not a blocker for this PR

@gakonst gakonst merged commit e1d66b8 into gakonst:master Mar 10, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants