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

Usage of bytes(uint) is ambiguous #14046

Closed
adaki2004 opened this issue Mar 13, 2023 · 9 comments
Closed

Usage of bytes(uint) is ambiguous #14046

adaki2004 opened this issue Mar 13, 2023 · 9 comments
Projects

Comments

@adaki2004
Copy link

Description

Usage of bytes(uint) conversion is ambiguous.

Here is a demonstration of usage - running a simple foundry test.

You can see, it seems like it produces empty bytes, but when it is hashed (keccak256) the output is different, meaning there is something else under the hood.

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "forge-std/Test.sol";
import "forge-std/console.sol";

contract FooBar {
   
    function debugBytesConversion() public {
        address dummyCanonicalTokenAddress = address(this);
        uint256 chainId = 1;
        uint256 chainId2 = 2;

        bytes memory concatenation =
                bytes.concat(
                    bytes32(chainId)
        );

        console.log("Output with chain ID 1 if not keccak hashed:");
        console.log(string(abi.encodePacked(concatenation)));

        bytes memory concatenation2 =
                bytes.concat(
                    bytes32(chainId2)
                );

        console.log("Output with chain ID 2 if not keccak hashed:");
        console.log(string(abi.encodePacked(concatenation2)));


        console.log("Output with chain ID 1 if keccak hashed:");
        console.log(string(abi.encodePacked(keccak256(concatenation))));


        console.log("Output with chain ID 2 if keccak hashed:");
        console.log(string(abi.encodePacked(keccak256(concatenation2))));
    }
}

contract EmptyBytesTest is Test {
    FooBar foobar;

    function setUp() public {
        foobar = new FooBar();
    }

    function testBytes() external {
        foobar.debugBytesConversion();
    } 
}

Environment

  • Compiler version: 0.8.18 but tried with different.
  • Framework/IDE (e.g. Truffle or Remix): Foundry for example - but issue visible if i write tests in Hardhat.
  • EVM execution environment / backend / blockchain client: Testing env.
  • Operating system: MacOsX

Steps to Reproduce

See source code above.

@github-actions github-actions bot added this to Triage in Solidity Mar 13, 2023
@nikola-matic
Copy link
Collaborator

Hi @adaki2004 and thanks for the report. Do you mind posting the actual output of all of the console.log calls?

@adaki2004
Copy link
Author

Hey @nikola-matic !
Find attached in copied text form:

Logs:
  Output with chain ID 1 if not keccak hashed:
  
  Output with chain ID 2 if not keccak hashed:
  
  Output with chain ID 1 if keccak hashed:
  �-Rv;&���q~j2
               �KJ�°s-����
                          �
  Output with chain ID 2 if keccak hashed:
  @W���#��c����3!ʁ�u�:��Z�
  • screenshot:
    kép

@r0qs
Copy link
Member

r0qs commented Mar 14, 2023

@adaki2004 what happens if you do the following:

console.logBytes(concatenation);
// or
console.logBytes(abi.encodePacked(hex"0000000000000000000000000000000000000000000000000000000000000001"));

It seems more an issue with the foundry console.log than a compiler issue.

@adaki2004
Copy link
Author

adaki2004 commented Mar 14, 2023

Thanks @r0qs ! Will check in a minute but you can see my main problem below.
We wanted to optimize things, and meant to be the same, but it turns out it breaks our hardhat tests (obviously not the foundry ones, bc. they will pass), so this is why i'm asking.

key = string.concat(Strings.toString(chainId), ".", name);
// Line below is cheaper in gas but will break Hardhat tests
// key = string(bytes.concat(bytes32(chainId), bytes(name)));

@adaki2004
Copy link
Author

With console.logBytes:

  Output with chain ID 1 if not keccak hashed:
  
  Output with console logbytes:
  0x0000000000000000000000000000000000000000000000000000000000000001
  Output with chain ID 2 if not keccak hashed:
  
  Output with console logbytes:
  0x0000000000000000000000000000000000000000000000000000000000000002
  Output with chain ID 1 if keccak hashed:
  �-Rv;&���q~j2
               �KJ�°s-����
                          �
  Output with chain ID 2 if keccak hashed:
  @W���#��c����3!ʁ�u�:��Z�

@adaki2004
Copy link
Author

Seems like the bytes.concat or the bytes(uint) is messing with me.. :) Any recommendations ? @nikola-matic @r0qs

@r0qs
Copy link
Member

r0qs commented Mar 14, 2023

Thanks @r0qs ! Will check in a minute but you can see my main problem below. We wanted to optimize things, and meant to be the same, but it turns out it breaks our hardhat tests (obviously not the foundry ones, bc. they will pass), so this is why i'm asking.

Right. The problem is that not all ascii characters are printable, so you are getting the correct output as far as I'm concerned. For instance, if you do:

console.log(string(abi.encodePacked(hex"0000000000000000000000000000000000000000000000000000000000000061")));

You should get a as output.

key = string.concat(Strings.toString(chainId), ".", name);
// Line below is cheaper in gas but will break Hardhat tests
// key = string(bytes.concat(bytes32(chainId), bytes(name)));

Not really sure of what you want achieve here, but if you want to define some sort of unique identifier based on the name and chainId, you could just use it as bytes instead of string, no? E.g.:

console.logBytes32(keccak256(abi.encodePacked(chainId, name)));

@adaki2004
Copy link
Author

Yes, so what we are trying to do is to keep track of a mapping between a key (this is the key creation i copied above) and an address.
So for example on chain 1, bank contract is a
1.bank = 0x120189D......ABC

So the string of 1.bank is our key and important to use it kinda this way, because we reference it on several places in the contract or in the tests , clients, etc., also readability point of view it is.
On the other hand we wanted to optimze for gas..

@r0qs
Copy link
Member

r0qs commented Mar 15, 2023

hum...a bit tricky to focus on gas optimization while keeping readability, often this is not really the case. And honestly, I'd rather use a hash as a key.

But yeah, design discussions around this is out of scope of the issue. I'd suggest that you post your design questions in our forum, or our matrix channel or even Ethereum stack exchange, and we can continue discussions from there.

I'm closing this since it is not a compiler issue ;)

@r0qs r0qs closed this as completed Mar 15, 2023
Solidity automation moved this from Triage to Done Mar 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Solidity
  
Done
Development

No branches or pull requests

3 participants