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

electrum compatibility and P2SH addresses #37

Open
melaxon opened this issue Jun 4, 2020 · 9 comments
Open

electrum compatibility and P2SH addresses #37

melaxon opened this issue Jun 4, 2020 · 9 comments

Comments

@melaxon
Copy link
Contributor

melaxon commented Jun 4, 2020

Hello I noticed 2 things when I run such commands:
./hd-wallet-derive.php -g --key="xprv......" --addr-type=p2sh-segwit --preset=electrum

./hd-wallet-derive.php -g --key="yprv......" --addr-type=p2sh-segwit --preset=electrum

The first one is meaningless for those who wish to generate the same addresses in Electrum because Electrum will never generate 3bitcoinaddres... addresses from XPRV (or XPUB). There is no such an option (currently)

The second command will generate the same addresses and public keys as Electrum does from given YPRV (or YPUB) but pubkeyhash seems to be WRONG (or maybe I'm wrong and missed something).

To get the address balance I inquire electrumx using this code:

...
$pubkeyhash = !empty($array['pubkeyhash']) ? $array['pubkeyhash'] : fn_get_hash160($address, $addrCreator, $network);  //if pubkeyhash exists we'll use it
$data = Base58::decodeCheck($address);
$prefixByte = $data->slice(0, $network->getP2shPrefixLength())->getHex();
if ($prefixByte === $network->getP2shByte()) { // P2SH: BTC: 3.., LTC: M...
            $script = "a914" . $pubkeyhash . "87";
} 
elseif ($prefixByte === $network->getAddressByte()) { // P2PKH: BTC: 1..., LTC: L...
            $script = "76a914" . $pubkeyhash . "88ac";
}

$hash = hash('sha256', hex2bin($script));
$hsah = ReverseEndianness($hash);
$result = $electrum->blockchainAddressGetBalance($hsah);
...

In case of XPRV everything is okay. For YPRV, if I use pubkeyhashes generated by hd-wallet-derive ($array['pubkeyhash']) the balance is always zero. If I delete pubkeyhashes and calculate them with some function fn_get_hash160 it works smoothly.
I guess I have to look into Bitwasp code (?)

@dan-da
Copy link
Owner

dan-da commented Jun 4, 2020

hi @melaxon . Thx for the report.

The first one is meaningless for those who wish to generate the same addresses in Electrum because Electrum will never generate 3bitcoinaddres... addresses from XPRV (or XPUB). There is no such an option (currently)

Good observation. The --preset, aka Path Preset is only an aid for choosing the bip32 path. It's not attempting to emulate a particular wallet in every regard.

The second command will generate the same addresses and public keys as Electrum does from given YPRV (or YPUB) but pubkeyhash seems to be WRONG (or maybe I'm wrong and missed something).

I will need to look into this in more detail. It would be helpful if you can post an example YPRV or YPUB (without funds!) along with electrum and hd-wallet-derive derived value(s) that demonstrate the discrepancy.

I guess I have to look into Bitwasp code (?)

maybe. It's been pretty solid though.

@melaxon
Copy link
Contributor Author

melaxon commented Jun 4, 2020

ypub6Z5GQFUWdyxxA6cKP8ZKacJTvtpk6ao3P54tvvzPSPevYH752rYWW6REEd5u5R77VdmkcrzWJmDHGKwx3qRmA9m39T26FJg5LngyQKSnokw

The address with index 15 contains 0.00022 BTC

This key was used to generate addresses in my app. The addresses and public keys are identical with electrum

./hd-wallet-derive.php -g --key="ypub6Z5GQFUWdyxxA6cKP8ZKacJTvtpk6ao3P54tvvzPSPevYH752rYWW6REEd5u5R77VdmkcrzWJmDHGKwx3qRmA9m39T26FJg5LngyQKSnokw" --addr-type=p2sh-segwit --preset=electrum --numderive=20 > electrum-p2sh-segwit-xpub.txt

I cannot see pubkeyhash in electrum unfortunately.

The function that calculates the "correct" pubkeyhashes:

function fn_get_hash160($addressInput, $addrCreator, $network)
{
    $address = null;
    try {
       $address = $addrCreator->fromString($addressInput, $network)->getHash();
    } catch ( \BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException $e) {
       $errormessage = 'The address you entered is not valid: ' . $addressInput;
       echo "Error message: ".$errormessage;
    }
    $hash160 = bin2hex(getProtectedValue($address, 'buffer'));
    return $hash160;
}

function getProtectedValue($obj,$name)
{
    $array = (array)$obj;
    $prefix = chr(0).'*'.chr(0);
    return !empty($array[$prefix.$name]) ? $array[$prefix.$name] : false;
}

@dan-da
Copy link
Owner

dan-da commented Jun 4, 2020

ok, so what are the "correct" and "incorrect" pubkeyhash values you are seeing for index 0? (assuming that your fn_get_hash160() is producing correct results).

@melaxon
Copy link
Contributor Author

melaxon commented Jun 4, 2020

address 0
3Eezg77r6TK4rd9gHSDSyCJTLrpStzbn3i
616d3566dc438763b59480512e1a08db35e6e4e2 - incorrect (derived with hd-wallet-derive)
8e37c2be6eb697c05ab109f7c7e38bea12477dd4 - correct (calculated)

address 15
3HCvCZMV4Y4jYV59yVT3Lb4GehJLH3EzPu
e2b3802c91e9926f7ce91226d15d72d7584e952e
aa319669fca81e0fc8ada49f29490d8f0c06c806

@melaxon
Copy link
Contributor Author

melaxon commented Jun 4, 2020

examples of P2PKH:

1NR4KPhzQagzSUBGunPSuKbWN7vnS6r77Z
eae764bd4d55cd53eab21991e56cb5f9e859ae5d
eae764bd4d55cd53eab21991e56cb5f9e859ae5d

Did not try bc1 yet

@melaxon
Copy link
Contributor Author

melaxon commented Jun 4, 2020

bach32 is also okay
bc1quauz4ymap0wstrt8vn4lcnxj0wug6lnc6zsas5
e7782a937d0bdd058d6764ebfc4cd27bb88d7e78 - the same pabkeyhash calculated and derived

@dan-da
Copy link
Owner

dan-da commented Jun 5, 2020

hmm, I took a brief look at this. I was trying to compare with output from other tools, but I couldn't seem to find one supports ypub and also outputs the pubkeyhash. So, it's not immediately obvious which implementation is correct.

The hd-wallet-derive code that gets the pubkeyhas is pretty straight-forward, ie:

            $pubkey = $key->getPublicKey()->getHex();
            $pubkeyhash = $key->getPublicKey()->getPubKeyHash()->getHex();

So this is just calling into the Bitwasp bitcoin-php lib to do the heavy lifting. One would think that if pubkey is correct, then pubkeyhash should be also, but I haven't investigated further yet.

@melaxon
Copy link
Contributor Author

melaxon commented Jun 5, 2020

Now I'm pretty sure that the problem resides is Bitwasp code. First, I will search through their PRs as the version of bitcoin-php you use is far not the latest one and maybe the problem is already solved in later releases.

@dan-da
Copy link
Owner

dan-da commented Jun 6, 2020

fwiw, I updated composer require to latest bitwasp release (1.0.4), found one issue, and determined that hd-wallet-derive still generates the "incorrect" pubkeyhash.

$ ./hd-wallet-derive.php -g --key="ypub6Z5GQFUWdyxxA6cKP8ZKacJTvtpk6ao3P54tvvzPSPevYH752rYWW6REEd5u5R77VdmkcrzWJmDHGKwx3qRmA9m39T26FJg5LngyQKSnokw" --addr-type=p2sh-segwit --path='0/x' --numderive=1 --cols=address,pubkeyhash

+------------------------------------+------------------------------------------+
| address                            | pubkeyhash                               |
+------------------------------------+------------------------------------------+
| 3Eezg77r6TK4rd9gHSDSyCJTLrpStzbn3i | 616d3566dc438763b59480512e1a08db35e6e4e2 |
+------------------------------------+------------------------------------------+

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