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

Should we clarify when library code is linked vs embedded? #3985

Closed
swaldman opened this Issue Apr 24, 2018 · 2 comments

Comments

Projects
None yet
2 participants
@swaldman
Contributor

swaldman commented Apr 24, 2018

To my surprise, I get nice, fully-linked, deployable code if I compile this.

pragma solidity ^0.4.22;

import "https://github.com/OpenZeppelin/zeppelin-solidity/blob/c5d66183abcb63a90a2528b8333b2b17067629fc/contracts/token/ERC20/StandardToken.sol";

// modified from https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/examples/SimpleToken.sol
contract SimpleToken is StandardToken {
  string public constant name = "SimpleToken"; 
  string public constant symbol = "SIMPLETOKEN"; 
  uint8 public constant decimals = 18; 

  uint256 public constant INITIAL_SUPPLY = 10000 * (10 ** uint256(decimals));

  constructor public {
    totalSupply_ = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
    Transfer(0x0, msg.sender, INITIAL_SUPPLY);
  }
}

That surprised me (pleasantly), because the imported parent contract (indirectly) depends on Zeppelin's SafeMath library. I expected the code to include __SafeMath__..._ placeholders that would have to be linked.

I'm happy, it works, yay! But in the documentation, I can't find an explanation of when the compiler would expect to link to a library, and when it would just embed library functionality into the generated code. Pretty much all of the discussion of libraries presumes they would be separately deployed and linked.

I'd be glad to try to update the docs, if I understood the rules for when library functionality is inlined-vs-linked myself. But I don't. Can anyone help?


p.s. I am using my own tooling, rather than solc to resolve imports (maybe that's why this works? because solc sees everything in a single compilation unit?) I've placed the fully resolved generated solidity here, fwiw.

@swaldman swaldman changed the title from Should we clarify when library code is linked vs embedded to Should we clarify when library code is linked vs embedded? Apr 24, 2018

@GNSPS

This comment has been minimized.

Contributor

GNSPS commented Apr 24, 2018

When utilizing internal functions from libraries these are inlined (since it would really just be a waste of gas to not do so in most cases).

@swaldman

This comment has been minimized.

Contributor

swaldman commented Apr 24, 2018

@GNSPS Thanks!

That seems like a good thing to document very clearly. (It seems like a very useful trick, to get the code reuse without the complexity of an extra module and a linkage and post-hack nervousness over the security of DELEGATECALL-based constructs.)

I see in the docs an example of a library built with internal functions, and an explanation that libraries are in the "context" of the using contract, and so can access them. From that, along with the explanation that internal functions are implemented as jumps within the code, a smarter reader than me might have been able to deduce that they would be inlined, but this seems like a feature that could be highlighted a bit more.

Now that I know what I am looking for, I see that this behavior is more explicitly documented here

Furthermore, internal functions of libraries are visible in all contracts, just as if the library were a base contract. Of course, calls to internal functions use the internal calling convention, which means that all internal types can be passed and memory types will be passed by reference and not copied. To realize this in the EVM, code of internal library functions and all functions called from therein will at compile time be pulled into the calling contract, and a regular JUMP call will be used instead of a DELEGATECALL.

Still, having read that page before and not understood the implication (that no separate library would need to be deployed if only internal functions are used), it might be worth highlighting a bit. I'll try to give that a shot.

Anyway, thank you again for resolving the mystery.

@swaldman swaldman closed this Apr 24, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment