Bit-Wasp / bitcoin-php

Bitcoin implementation in PHP
The Unlicense
1.05k stars 414 forks source link

How to get addresses from outputs of raw transaction? #577

Open Vasiliy-Bondarenko opened 6 years ago

Vasiliy-Bondarenko commented 6 years ago

Here is real transaction - i need to extract all output addresses there is no method like getAdrress() or similar on the output object...

            $tx = TransactionFactory::fromHex("0100000001476a9d32181de5381c18c3c5aad36fcb78cbadfd1ae69e2659e1d22cea805ffd010000006b48304502210092bb009c9fd961310f7d4b4538c4e9bb9c9020398b9820b5b65c77d2f1b7dfea0220609947199c8d4c857ad7cfce7a0e6bf335f384ddaf6dbf60304bb77701736f33012102947388504d6969d581cc72bc6824a3045f3e9805d9c954f8a5401492c923c678feffffff04006cdc02000000001976a9149bfedc6be7f80062ca77a49a8f6d9604398023fc88ac7ce10b00000000001976a9145e8f7daea735fb6ddb1796b1ae8eeda40234728388ac546af122000000001976a914d43967f1ff57716d38519f02563b6b6b20ef039788ac00a60e00000000001976a91406f93b94aab2a912d9335756dd02cdcff1796f5188aced980700");
            $addresses = [];

            foreach ($tx->getOutputs() as $output) {
                $addresses[] = $output->???
            }

This transaction on the network: https://live.blockcypher.com/btc/tx/e9cc2041e5b7a8733aa3706586c27a935d593c4dbf4178ebff0b24716d1d62d2/

afk11 commented 6 years ago

Check out the AddressFactory class, it has functions for parsing addresses from various things: https://github.com/Bit-Wasp/bitcoin-php/blob/7ac9fbe477ac437883cd180bc01006ecb6b6c5f9/src/Address/AddressFactory.php

try {
    $address = AddressFactory::fromOutputScript($output->getScript());
    echo $address->getAddress(/*$network*/); // defaults to globally set network, otherwise pass one to encode for that network specifically.
    $addresses[] = $address;

} catch (\Exception $e) {
}

or copy some code from that function if you're doing it in a long running process (so you can reuse the OutputClassifier), and instead of throwing an exception just skip parsing the address if it's not P2PKH/P2SH.

Vasiliy-Bondarenko commented 6 years ago

Thank you. I've got my error. I was decoding on testnet instead of real network. silly me :)

By the way - in AddressFactory some \RuntimeException's are thrown. And it's not very good solution.

F.ex. i call fromOutputScript() and i want to just skip the script not associated with address. But now i must check the text of the exception message because i can not rely on general-type exception like \RuntimeException - it can be thrown by any other part of the code (because i have more then one method call in try-catch block). It would be better to throw more specific exceptions like ScriptNotAssociatedWithAddress which can extend the same \RuntimeException (for backwards compatibility). And the same is true for every other general type exceptions.

At first it looks too verbose, but works much better when you actually use this code.

afk11 commented 6 years ago

Oops, thought I responded to this already! You're definitely right, I'll work on this. Probably just add it to master, but as mentioned in the litecoin bytes thread I'm not sure if we need an 0.0.35? If it's worth considering before master, again let me know.

Vasiliy-Bondarenko commented 6 years ago

to me both are definitely not urgent. I’m easily extending NetworkFactory with my own settings and this issue is also not critical.

toknT commented 4 years ago

in current version

bitwasp/bitcoin                       v1.0.4             PHP Bitcoin library with functions for transactions, signatures, serialization, Random/Deterministic ECDSA keys, blocks, RPC bindings

it will be

$addressReader = new AddressCreator();
$address = $addressReader->fromOutputScript($output->getScript())->getAddress();

but will throw exception if has invalid script ,don't forget catch the exception.