-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Added isAddress() validation method #134
Conversation
so I realise now many tests depend on the methods in Numeric.java and Hash.java to remain as they are. Therefore I have kept them as they are, and use the method in Hash.java that accepts a byte array directly. |
Codecov Report
@@ Coverage Diff @@
## master #134 +/- ##
============================================
+ Coverage 78.77% 78.77% +<.01%
- Complexity 1241 1251 +10
============================================
Files 181 182 +1
Lines 4339 4358 +19
Branches 662 668 +6
============================================
+ Hits 3418 3433 +15
- Misses 742 743 +1
- Partials 179 182 +3
Continue to review full report at Codecov.
|
Hi @assafY, please can you provide a unit test that demonstrates this error you believe exists in hexStringToByteArray? |
Sure, but it would be useful if you told me first whether you intended for hexStringToByteArray to transform a String into a byte array in a similar way that String.getBytes() does? Because the two return different results for the same string, so if that was the intention I can quickly write a unit test that demonstrates this error. |
If you call String.getBytes() on a hex string, you get the ASCII values for each of the characters in the String. This is not the same as a byte array which is a binary encoded array of data. E.g. "123".getBytes() == new byte[] { '1', '2', '3'} Or equivalently: new byte[] { (byte) 49, (byte) 50, (byte) 51 }; Whereas with a byte array (remember the 123 is a hex not decimal value here): hexStringToByteArray("123") == new byte[] { (byte) 1, (byte) 35 } |
I understand - so I am assuming that the checksum validation for newer Ethereum account addresses, as described here, uses the ASCII value byte representation rather than the one you implemented in hexStringToByteArray. In this case I think the comparison between the two is irrelevant, and the checksum validation method I added which uses getBytes works independently. Checksum validation is now used by most major ether wallets and I assumed it would be a useful addition to the Web3j library. |
Hi, I try to validate a address but cant pass.Maybe this line |
That is correct, thanks! You do need |
@@ -38,7 +38,7 @@ public static Boolean isAddress(String address) { | |||
|
|||
private static Boolean validateChecksumAddress(String address) { | |||
String formattedAddress = address.replace("0x", "").toLowerCase(); | |||
String hash = Numeric.toHexString(Hash.sha3(formattedAddress.getBytes())); | |||
String hash = Numeric.toHexStringNoPrefix(Hash.sha3(formattedAddress.getBytes())); | |||
for (int i = 0; i < 40; i++) { | |||
if (Character.isLetter(address.charAt(i))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you check from the address? This seems to be wrong - address still contains the leading '0x'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I missed that method. In this case you can also remove the .replace("0x", "")
above, which I assumes is what happens in toHexStringNoPrefix
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I misunderstood your question. This is actually the correct way to do it. The hash needs to be computed from the lowercase address without a prefix, but the validation of the hash should happen against the original, untouched address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I don't think that you can remove it - if you remove it it would be used in the sha3 hashing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compare with
https://ethereum.stackexchange.com/questions/1374/how-can-i-check-if-an-ethereum-address-is-valid
especially this line:
address = address.replace('0x','');
using the untouched address with leading '0x' is false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh you are correct - thank you for pointing that out. The checksum validation should be carried out on the address without the 0x prefix. Fixed that now, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now you are ussing the lower cased version also in the comparision - thats not right.
Character.isUpperCase(address.charAt(i)) && charInt <= 7
can never happen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slow day for me today isn't it? Fixed that now, thanks.
@@ -38,7 +38,7 @@ public static Boolean isAddress(String address) { | |||
|
|||
private static Boolean validateChecksumAddress(String address) { | |||
String formattedAddress = address.replace("0x", "").toLowerCase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to validate eth addresses in a current project - I modified your version:
String formattedAddress = address.replace("0x", ""); String lowercaseAddress = formattedAddress.toLowerCase(); String hash = Numeric.toHexStringNoPrefix(Hash.sha3(lowercaseAddress.getBytes())); for (int i = 0; i < 40; i++) { if (Character.isLetter(formattedAddress.charAt(i))) {
Some tests wouldn't be bad |
anything stopping this from being merged? |
* @param address given address in HEX | ||
* @return is this a valid address | ||
*/ | ||
public static Boolean isAddress(String address) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WalletUtils.isValidAddress achieves similar functionality.
} | ||
} | ||
|
||
private static Boolean validateChecksumAddress(String address) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validating checksum addresses is useful functionality.
It might be better to have isChecksumAddress as a method on the Address type, and a toChecksumAddress that operates on an Address or String instance
See comments. It's also useful to reference the original EIP for checksum addresses ethereum/EIPs#55, and include the corresponding issue in your commits. I'd recommend you create a brand new PR, as there are a lot of commits in this PR. Thanks for taking the time to get this far. |
While using the Web3j Numeric and Hash libraries to implement a isAddress() method in a local project, I have realised the method hexStringToByteArray() is not only unnecessary (you can just use the native .getBytes() on a string), but also returns an incorrect byte array.
To verify this, the isAddress() method in this PR fails if using the aforementioned method, but works if using the native .toBytes().
I have therefore removed the method content and replaced it simply with .getBytes(), and implemented the isAddress() method in a new class . This method is based on the web3.js implementation and is working perfectly in my own project.