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

Solidity packing doesn't support arrays #27

Open
raineorshine opened this issue Aug 10, 2016 · 16 comments
Open

Solidity packing doesn't support arrays #27

raineorshine opened this issue Aug 10, 2016 · 16 comments

Comments

@raineorshine
Copy link

I have been trying to reproduce Solidity's sha3 in Javascript, and have gotten everything to work with my own code except arrays. Once I found out about this library, I tried to use it for arrays, but I haven't been able to get the same hash as Solidity produces yet. It would be great if you might be able to help me understand this better.

How would I generate the same sha3 hash using ethereumjs-abi as in this Solidity example?

contract Contract {
    function Test() constant returns(bytes32) {
        uint[] memory amounts = new uint[](2);
        amounts[0] = 1;
        amounts[1] = 2;

        bytes8[] memory tickers = new bytes8[](2);
        tickers[0] = "BTC";
        tickers[1] = "LTC";

        // 0x4282aea708b799612aa9d311309ef4b8eb1374cf0740c3e9d5914cb5ce9b93f2
        return sha3(amounts, tickers);
    }
}

My attempt gives an error of Cannot read property 1 of undefined:

abi.soliditySHA3(['uint[]', 'bytes8[]'], [[1,2], ['BTC', 'LTC']])
@axic
Copy link
Member

axic commented Aug 10, 2016

There was a bug in using the shorthand-types (i.e. uint) in master a while ago. Yet to release it.

Either use the master or change uint to uint256.

@raineorshine
Copy link
Author

> soliditySHA3(['uint256[]', 'bytes8[]'], [[1,2], ['BTC', 'LTC']])
TypeError: Cannot read property '1' of null
    at parseTypeN (/Users/raine/projects/tags/node_modules/ethereumjs-abi/lib/index.js:42:42)
    at Function.ABI.solidityPack (/Users/raine/projects/tags/node_modules/ethereumjs-abi/lib/index.js:454:14)
    at ABI.soliditySHA3 (/Users/raine/projects/tags/node_modules/ethereumjs-abi/lib/index.js:487:25)
    at repl:1:1
    at REPLServer.defaultEval (repl.js:252:27)
    at bound (domain.js:287:14)
    at REPLServer.runBound [as eval] (domain.js:300:12)
    at REPLServer.<anonymous> (repl.js:417:12)
    at emitOne (events.js:95:20)
    at REPLServer.emit (events.js:182:7)

@axic
Copy link
Member

axic commented Aug 29, 2016

@raineorshine you are right it doesn't support arrays.

I would like to rework the library and make the types ES6 classes. That should simplify both the encoding/decoding and the solidity packing. Are you interested in helping out?

@axic axic changed the title How to sha3 arrays Solidity packing doesn't support arrays Aug 29, 2016
@raineorshine
Copy link
Author

@axic Very interested, but definitely too busy the next couple weeks as I finish up a project and prep for Devcon2. Watching the thread though! Might have time next month.

@djrtwo
Copy link
Contributor

djrtwo commented Aug 16, 2017

@axic @raineorshine I'm working on implementing a soliditySha3 function in python but can't figure out how the values are packed for arrays. Do either of you know/have a link to documentation?

Thanks

@raineorshine
Copy link
Author

@djrtwo Maybe here? https://github.com/brix/crypto-js/blob/develop/src/sha3.js

Not sure; I know it was added to web3-utils.

@djrtwo
Copy link
Contributor

djrtwo commented Aug 17, 2017

Solidity packs values from arrays as size 256 regardless of type.

So in Solidity:
uint8[] uint8Array = [8, 9]; keccak256(uint8Array);
is equivalent to:
keccak256(hex'00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009');
rather than what i expected:
keccak256(hex'0809');

Same goes for arrays of all other fixed types. 160bit addresses are padded to 256bits, Booleans (0x01, 0x00) are padded to 256 bits.

I might get arrange to implementing this in this library sometime, but if someone gets to it first, I wanted y'all to know! Took me tracing a Solidity call to figure it out...

Cheers!

@holgerd77
Copy link
Member

Not sure, is this still an issue?

@raineorshine
Copy link
Author

Is there a test for it? If not, I'd guess it still exists.

@tommyz7
Copy link

tommyz7 commented Dec 30, 2018

For the time being (as @djrtwo explained) you can do the following:

contract GenHash {
    function getHash(string title, uint256 num, address[] addr, uint256 num2) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(title, num, addr, num2));
    }
}

and in JS..

function getHash(title, num, arr, num2) {
  let args = []
  arr.map((addr, index) => {
    args[index] = {t: 'bytes', v: web3.utils.leftPad(addr, 64)}
  })
  return web3.utils.soliditySha3(
    {t: 'string', v: title},
    {t: 'uint256', v: num},
    ...args,
    {t: 'uint256', v: num2}
  );
}

@danjm
Copy link

danjm commented Jun 3, 2019

There appear to be two PRs which attempt to resolve this issue #47 and #50. The algorithms used in each are fairly different. I will review each and run each against a more robust set of test cases, then move forward the most appropriate PR.

@holgerd77
Copy link
Member

@danjm sounds good!

@forshtat
Copy link
Contributor

@danjm @holgerd77 Hello. Any progress on this one, by chance? I mean, this issue is quite frustrating and prevents us from using the released version of the module, and also, just saying, this is very basic functionality that has been reported missing since the year 2016, and I see that two pull requests with fixes were already made. Do you need any assistance with this, maybe? Will be glad to help. Thanks!

@holgerd77
Copy link
Member

@alex-forshtat-tbk Sorry, we just have too many libraries to maintain with too few people. Could you eventually give some short comparison of the two PRs open and give some opinion which one you prefer?

@forshtat
Copy link
Contributor

forshtat commented Aug 1, 2019

@holgerd77 Without diving too deep, in my opinion, the PR #47 extracts a nice piece of solidity encoding logic into a 'solidityHexValue' function that encapsulates a hex representation of solidity types and has a cute recursive special condition for arrays, that guarantees multi-dimensional array support. Also, it passes the tests.

In comparison, #50 is a complete mess. "toSolidityBytes32" is added, but not used by the commit itself, and the code basically duplicates everything again inside 'isArray' branch for no reason. Multi-dimensional arrays are not supported.

@holgerd77
Copy link
Member

@alex-forshtat-tbk thanks, very helpful! I will try to use the "Update branch" function from GitHub and manually resolve conflicts in the next couple of days, since the original author of the PR is not responsive anymore (which is no wonder 😛).

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

No branches or pull requests

8 participants
@axic @raineorshine @holgerd77 @djrtwo @danjm @tommyz7 @forshtat and others