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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize Strings.toString(uint) implementation #3190

Closed
3sGgpQ8H opened this issue Feb 12, 2022 · 6 comments
Closed

Optimize Strings.toString(uint) implementation #3190

3sGgpQ8H opened this issue Feb 12, 2022 · 6 comments

Comments

@3sGgpQ8H
Copy link

馃 Motivation
The current Strings.toString(uint) implementation is quite inefficient on large inputs.

馃摑 Details
Consider optimizing it as suggested here: https://stackoverflow.com/a/71095692/2038768

@frangio
Copy link
Contributor

frangio commented Feb 17, 2022

Thank you @3sGgpQ8H. Can you elaborate on what exactly makes the current implementation inefficient and what is the reason we would see an improvement with the link you shared?

@3sGgpQ8H
Copy link
Author

Sure.

  1. The current implementation uses linear search to find out the number of digits in the result, while binary search would be much more efficient: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol#L22-L27
  2. In the current implementation, the main loop evaluate loop condition after every digit, which is a significant overhead. Unrolling the loop could save much gas.

@frangio
Copy link
Contributor

frangio commented Feb 19, 2022

Got it. Agree with the first point. Perhaps we should have a general purpose Math.log10 and use that function here?

For the second point we need to consider that toString returns a string of arbitrary length so I'm not sure how that plays together with the loop unrolling.

As a side note, do you see this function being used on-chain as opposed to off-chain queries?

@3sGgpQ8H
Copy link
Author

I'm not sure how that plays together with the loop unrolling.

Look at the StackOverflow answer referred in the original post.

As a side note, do you see this function being used on-chain as opposed to off-chain queries?

Surely, its its primary purpose is to be used on-chain. For off-chain use it would be more efficient to return a number and convert to a string off-chain (i.e. in UI). Two quite common on-chain usages are:

  1. Include a number into a signed message whose signature is verified by a smart contract (a message has to be human readable, thus numbers are included in decimal format)
  2. Append a token ID to a ERC-721 NFT URI

@frangio
Copy link
Contributor

frangio commented Feb 22, 2022

I hadn't realized the StackOverflow answer was Solidity. 馃檪

Signatures are a decent use case, though a standard like EIP712 doesn't convert them to decimal format. NFT URIs are not normally computed on chain as far as I know.

In any case I think it makes sense to optimize this.

@frangio
Copy link
Contributor

frangio commented Sep 16, 2022

Fixed by #3573 where toString was changed to binary search (see also the new log functions from #3670).

We haven't unrolled the loop. We can consider that if someone wants to open a PR and it shows significant savings.

@frangio frangio closed this as completed Sep 16, 2022
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

No branches or pull requests

2 participants