user54226: I'm trying to "extract" sender's addresses from OP_RETURN Bitcoin transactions, but my code is not working properly.

getWalletAddressOfSender(final Transaction tx)

public static Address getWalletAddressOfSender(final Transaction tx) {

    Address fromAddress = null;

    for (final TransactionInput ti : tx.getInputs()) {

        try {

            Script scriptSig = ti.getScriptSig();
            List<ScriptChunk> chunks = scriptSig.getChunks();

            byte[] pubKey = scriptSig.getPubKey();
            fromAddress = new Address(MainNetParams.get(), Utils.sha256hash160(pubKey));// scriptSig.getFromAddress(MainNetParams.get());

            return fromAddress;

        } catch (final ScriptException x) {
            System.out.println(x.getMessage());
        }
    }

    return null;
}

When the TransactionInput is from a address starting with 3... (P2SH) the list 'scriptSig.getChunks()' will have 5 items and 'getPubKey()' will throw the exception 'Script not of right size, expecting 2 but got 5'.

scriptSig.getPubKey()

/**
 * Returns the public key in this script. If a script contains two constants and nothing else, it is assumed to
 * be a scriptSig (input) for a pay-to-address output and the second constant is returned (the first is the
 * signature). If a script contains a constant and an OP_CHECKSIG opcode, the constant is returned as it is
 * assumed to be a direct pay-to-key scriptPubKey (output) and the first constant is the public key.
 *
 * @throws ScriptException if the script is none of the named forms.
 */
public byte[] getPubKey() throws ScriptException {
    if (chunks.size() != 2) {
        throw new ScriptException("Script not of right size, expecting 2 but got " + chunks.size());
    }
    final ScriptChunk chunk0 = chunks.get(0);
    final byte[] chunk0data = chunk0.data;
    final ScriptChunk chunk1 = chunks.get(1);
    final byte[] chunk1data = chunk1.data;
    if (chunk0data != null && chunk0data.length > 2 && chunk1data != null && chunk1data.length > 2) {
        // If we have two large constants assume the input to a pay-to-address output.
        return chunk1data;
    } else if (chunk1.equalsOpCode(OP_CHECKSIG) && chunk0data != null && chunk0data.length > 2) {
        // A large constant followed by an OP_CHECKSIG is the key.
        return chunk0data;
    } else {
        throw new ScriptException("Script did not match expected form: " + this);
    }
}

So i changed the code to
public static Address getWalletAddressOfSender(final Transaction tx) {

    Address fromAddress = null;

    for (final TransactionInput ti : tx.getInputs()) {

        try {
            Script scriptSig = ti.getScriptSig();
            List<ScriptChunk> chunks = scriptSig.getChunks();
            if(chunks.size() > 2) {
                System.out.print("This is a 5 chunks transaction... ");
                byte[] pubKeyHash = scriptSig.getPubKeyHash();
                fromAddress = Address.fromP2SHHash(MainNetParams.get(), pubKeyHash);
            } else {
                byte[] pubKey = scriptSig.getPubKey();
                fromAddress = new Address(MainNetParams.get(), Utils.sha256hash160(pubKey));// scriptSig.getFromAddress(MainNetParams.get());   
            }

            return fromAddress;
        } catch (final ScriptException x) {
            System.out.println(x.getMessage());
        }
    }

    return null;
}

but it will also throw another exception 'Script not in the standard scriptPubKey form' (when chunks.size() > 2)

scriptSig.getPubKeyHash()

/**
 * <p>If a program matches the standard template DUP HASH160 &lt;pubkey hash&gt; EQUALVERIFY CHECKSIG
 * then this function retrieves the third element.
 * In this case, this is useful for fetching the destination address of a transaction.</p>
 * 
 * <p>If a program matches the standard template HASH160 &lt;script hash&gt; EQUAL
 * then this function retrieves the second element.
 * In this case, this is useful for fetching the hash of the redeem script of a transaction.</p>
 * 
 * <p>Otherwise it throws a ScriptException.</p>
 *
 */
public byte[] getPubKeyHash() throws ScriptException {
    if (isSentToAddress())
        return chunks.get(2).data;
    else if (isPayToScriptHash())
        return chunks.get(1).data;
    else
        throw new ScriptException("Script not in the standard scriptPubKey form");
}


Here's a transaction where chunks.size() == 2 and i'm able to extract
  sender's address (1KYiKJEfdJtap9QX2v9BXJMpz2SfU4pgZw)

https://www.blockchain.com/btc/tx/b5765d54e275794939eb48c77dd8862a6e865dee6d71bc7004660dca32de8c43

These are some transactions where chunks.size() == 5 and i'm NOT able to
  extract the sender's address (3....)

https://www.blockchain.com/btc/tx/b02e17479660a4685daba4e8f0f73aea96e0c36ab14142b68f868ac76a77455a
https://www.blockchain.com/btc/tx/f0a6708167eca88b9fe4dad4c110ddff2b3f6c5e08771793b8ca40400d4effab
https://www.blockchain.com/btc/tx/28a91393393916367e890965200d4f8af04416b65ee6fea22c0adf29af8ea3b8
What's the correct way of getting the sender's address in these cases ?
FYI: here's my shitty method to get the recipient's address
// THIS IF A FUCKED UP WORKAROUND, FIX ASAP
@Nullable
public static Address getWalletAddressOfReceiver(final Transaction tx, final Address senderAddress) {

    for (final TransactionOutput output : tx.getOutputs()) {
        try {
            final Script script = output.getScriptPubKey();     
            Address receiverAddress = script.getToAddress(MainNetParams.get(), true);
            if(receiverAddress.equals(senderAddress))
                continue;
            return receiverAddress;

        } catch (final ScriptException x) {

        }
    }

    return null;
}

As the recipient's address is in a random position in "tx.getOutputs()" i just skip it if it's equal to sender's address and get the next one.

user91320: When an input redeems a P2PKH output (pay to an address starting with a 1), the format of the input script (the scriptSig) is: [signature] [public key]. Because public keys are included in both standard input scripts (redeeming P2PKH outputs) and output scripts (P2PK), the Script.getPubKey() method has been written to return the public key in either input scripts or output scripts, hence it can work for you here.
Public key hashes (addresses), however, are only included in standard output scripts. So the Script.getPubKeyHash() method assumes you're talking about an output script, so it won't work for you here.
An input script redeeming a P2SH (pay to address starting with a 3) output is not necessarily 5 chunks, but the address is the hash of the redeem script, and the redeem script is always the last chunk. (Specifically, the input script is: [script sig for the redeem script (may be multiple chunks)] [redeem script].) So all you'll need to do is get the last chunk (which is also what you're doing for P2PKH) and hash it.
The one place you might run into trouble is if you're redeeming a P2SH output, and the input script is 2 chunks. (This could come up, for instance, if the redeem script is [public key] OP_CHECKSIG - then the sigScript would be in the form [signature] [20-byte hash], indistinguishable from one redeeming a P2PKH output.) The way to check this would be to look at the previous transaction and check its output scripts (which would also give you the addresses you're looking for more easily).
But assuming that when you redeem P2SH outputs the input script is more than 2 chunks, something like this should work:
public static Address getWalletAddressOfSender(final Transaction tx) {

    Address fromAddress = null;

    for (final TransactionInput ti : tx.getInputs()) {

        try {

            Script scriptSig = ti.getScriptSig();
            List<ScriptChunk> chunks = scriptSig.getChunks();

            byte[] pubKey = chunks.get(chunks.size() - 1).data;
            byte[] pubKeyHash = Utils.sha256hash160(pubKey);

            if (chunks.size() > 2) { // assume P2SH
                fromAddress = Address.fromP2SHHash(MainNetParams.get(), pubKeyHash);
            } else if (chunks.size() == 2) { // assume P2PKH
                fromAddress = new Address(MainNetParams.get(), pubKeyHash);
            }
            return fromAddress;

        } catch (final ScriptException x) {
            System.out.println(x.getMessage());
        }
    }

    return null;
}

(Note I used the variable names pubKey and pubKeyHash here, but in the case of P2SH these will instead be a script and a script hash. This method could also cause problems if the output being referenced is a multisig, P2PK, or something non-standard.)
I also notice your method only returns the first sender address. If a transaction has inputs from multiple sources, it might be worth returning a list or a set of those sender addresses. Just a thought.
Hope this helps!

54226: <p>I'm trying to "extract" sender's addresses from OP_RETURN Bitcoin transactions, but my code is not working properly.</p>

<blockquote>
  <p>getWalletAddressOfSender(final Transaction tx)</p>
</blockquote>

<pre><code>public static Address getWalletAddressOfSender(final Transaction tx) {

    Address fromAddress = null;

    for (final TransactionInput ti : tx.getInputs()) {

        try {

            Script scriptSig = ti.getScriptSig();
            List&lt;ScriptChunk&gt; chunks = scriptSig.getChunks();

            byte[] pubKey = scriptSig.getPubKey();
            fromAddress = new Address(MainNetParams.get(), Utils.sha256hash160(pubKey));// scriptSig.getFromAddress(MainNetParams.get());

            return fromAddress;

        } catch (final ScriptException x) {
            System.out.println(x.getMessage());
        }
    }

    return null;
}
</code></pre>

<p>When the TransactionInput is from a address starting with 3... (P2SH) the list 'scriptSig.getChunks()' will have 5 items and 'getPubKey()' will throw the exception 'Script not of right size, expecting 2 but got 5'.</p>

<blockquote>
  <p>scriptSig.getPubKey()</p>
</blockquote>

<pre><code>/**
 * Returns the public key in this script. If a script contains two constants and nothing else, it is assumed to
 * be a scriptSig (input) for a pay-to-address output and the second constant is returned (the first is the
 * signature). If a script contains a constant and an OP_CHECKSIG opcode, the constant is returned as it is
 * assumed to be a direct pay-to-key scriptPubKey (output) and the first constant is the public key.
 *
 * @throws ScriptException if the script is none of the named forms.
 */
public byte[] getPubKey() throws ScriptException {
    if (chunks.size() != 2) {
        throw new ScriptException("Script not of right size, expecting 2 but got " + chunks.size());
    }
    final ScriptChunk chunk0 = chunks.get(0);
    final byte[] chunk0data = chunk0.data;
    final ScriptChunk chunk1 = chunks.get(1);
    final byte[] chunk1data = chunk1.data;
    if (chunk0data != null &amp;&amp; chunk0data.length &gt; 2 &amp;&amp; chunk1data != null &amp;&amp; chunk1data.length &gt; 2) {
        // If we have two large constants assume the input to a pay-to-address output.
        return chunk1data;
    } else if (chunk1.equalsOpCode(OP_CHECKSIG) &amp;&amp; chunk0data != null &amp;&amp; chunk0data.length &gt; 2) {
        // A large constant followed by an OP_CHECKSIG is the key.
        return chunk0data;
    } else {
        throw new ScriptException("Script did not match expected form: " + this);
    }
}
</code></pre>

<p>So i changed the code to</p>

<pre><code>public static Address getWalletAddressOfSender(final Transaction tx) {

    Address fromAddress = null;

    for (final TransactionInput ti : tx.getInputs()) {

        try {
            Script scriptSig = ti.getScriptSig();
            List&lt;ScriptChunk&gt; chunks = scriptSig.getChunks();
            if(chunks.size() &gt; 2) {
                System.out.print("This is a 5 chunks transaction... ");
                byte[] pubKeyHash = scriptSig.getPubKeyHash();
                fromAddress = Address.fromP2SHHash(MainNetParams.get(), pubKeyHash);
            } else {
                byte[] pubKey = scriptSig.getPubKey();
                fromAddress = new Address(MainNetParams.get(), Utils.sha256hash160(pubKey));// scriptSig.getFromAddress(MainNetParams.get());   
            }

            return fromAddress;
        } catch (final ScriptException x) {
            System.out.println(x.getMessage());
        }
    }

    return null;
}
</code></pre>

<p>but it will also throw another exception 'Script not in the standard scriptPubKey form' (when chunks.size() > 2)</p>

<blockquote>
  <p>scriptSig.getPubKeyHash()</p>
</blockquote>

<pre><code>/**
 * &lt;p&gt;If a program matches the standard template DUP HASH160 &amp;lt;pubkey hash&amp;gt; EQUALVERIFY CHECKSIG
 * then this function retrieves the third element.
 * In this case, this is useful for fetching the destination address of a transaction.&lt;/p&gt;
 * 
 * &lt;p&gt;If a program matches the standard template HASH160 &amp;lt;script hash&amp;gt; EQUAL
 * then this function retrieves the second element.
 * In this case, this is useful for fetching the hash of the redeem script of a transaction.&lt;/p&gt;
 * 
 * &lt;p&gt;Otherwise it throws a ScriptException.&lt;/p&gt;
 *
 */
public byte[] getPubKeyHash() throws ScriptException {
    if (isSentToAddress())
        return chunks.get(2).data;
    else if (isPayToScriptHash())
        return chunks.get(1).data;
    else
        throw new ScriptException("Script not in the standard scriptPubKey form");
}
</code></pre>

<blockquote>
  <p>Here's a transaction where chunks.size() == 2 and i'm able to extract
  sender's address (1KYiKJEfdJtap9QX2v9BXJMpz2SfU4pgZw)</p>
</blockquote>

<p><a href="https://www.blockchain.com/btc/tx/b5765d54e275794939eb48c77dd8862a6e865dee6d71bc7004660dca32de8c43" rel="nofollow noreferrer">https://www.blockchain.com/btc/tx/b5765d54e275794939eb48c77dd8862a6e865dee6d71bc7004660dca32de8c43</a></p>

<blockquote>
  <p>These are some transactions where chunks.size() == 5 and i'm NOT able to
  extract the sender's address (3....)</p>
</blockquote>

<p><a href="https://www.blockchain.com/btc/tx/b02e17479660a4685daba4e8f0f73aea96e0c36ab14142b68f868ac76a77455a" rel="nofollow noreferrer">https://www.blockchain.com/btc/tx/b02e17479660a4685daba4e8f0f73aea96e0c36ab14142b68f868ac76a77455a</a></p>

<p><a href="https://www.blockchain.com/btc/tx/f0a6708167eca88b9fe4dad4c110ddff2b3f6c5e08771793b8ca40400d4effab" rel="nofollow noreferrer">https://www.blockchain.com/btc/tx/f0a6708167eca88b9fe4dad4c110ddff2b3f6c5e08771793b8ca40400d4effab</a></p>

<p><a href="https://www.blockchain.com/btc/tx/28a91393393916367e890965200d4f8af04416b65ee6fea22c0adf29af8ea3b8" rel="nofollow noreferrer">https://www.blockchain.com/btc/tx/28a91393393916367e890965200d4f8af04416b65ee6fea22c0adf29af8ea3b8</a></p>

<p>What's the correct way of getting the sender's address in these cases ?</p>

<p>FYI: here's my shitty method to get the recipient's address</p>

<pre><code>// THIS IF A FUCKED UP WORKAROUND, FIX ASAP
@Nullable
public static Address getWalletAddressOfReceiver(final Transaction tx, final Address senderAddress) {

    for (final TransactionOutput output : tx.getOutputs()) {
        try {
            final Script script = output.getScriptPubKey();     
            Address receiverAddress = script.getToAddress(MainNetParams.get(), true);
            if(receiverAddress.equals(senderAddress))
                continue;
            return receiverAddress;

        } catch (final ScriptException x) {

        }
    }

    return null;
}
</code></pre>

<p>As the recipient's address is in a random position in "tx.getOutputs()" i just skip it if it's equal to sender's address and get the next one.</p>
 91320: <p>When an input redeems a P2PKH output (pay to an address starting with a 1), the format of the input script (the scriptSig) is: <code>[signature] [public key]</code>. Because public keys are included in both standard input scripts (redeeming P2PKH outputs) and output scripts (P2PK), the <code>Script.getPubKey()</code> method has been written to return the public key in either input scripts or output scripts, hence it can work for you here.</p>

<p>Public key hashes (addresses), however, are only included in standard output scripts. So the <code>Script.getPubKeyHash()</code> method assumes you're talking about an <strong>output</strong> script, so it won't work for you here.</p>

<p>An input script redeeming a P2SH (pay to address starting with a 3) output is not necessarily 5 chunks, but the address is the hash of the redeem script, and the redeem script is always the last chunk. (Specifically, the input script is: <code>[script sig for the redeem script (may be multiple chunks)] [redeem script]</code>.) So all you'll need to do is get the last chunk (which is also what you're doing for P2PKH) and hash it.</p>

<p>The one place you might run into trouble is if you're redeeming a P2SH output, and the input script is 2 chunks. (This could come up, for instance, if the redeem script is <code>[public key] OP_CHECKSIG</code> - then the sigScript would be in the form <code>[signature] [20-byte hash]</code>, indistinguishable from one redeeming a P2PKH output.) The way to check this would be to look at the previous transaction and check its output scripts (which would also give you the addresses you're looking for more easily).</p>

<p>But assuming that when you redeem P2SH outputs the input script is more than 2 chunks, something like this should work:</p>

<pre><code>public static Address getWalletAddressOfSender(final Transaction tx) {

    Address fromAddress = null;

    for (final TransactionInput ti : tx.getInputs()) {

        try {

            Script scriptSig = ti.getScriptSig();
            List&lt;ScriptChunk&gt; chunks = scriptSig.getChunks();

            byte[] pubKey = chunks.get(chunks.size() - 1).data;
            byte[] pubKeyHash = Utils.sha256hash160(pubKey);

            if (chunks.size() &gt; 2) { // assume P2SH
                fromAddress = Address.fromP2SHHash(MainNetParams.get(), pubKeyHash);
            } else if (chunks.size() == 2) { // assume P2PKH
                fromAddress = new Address(MainNetParams.get(), pubKeyHash);
            }
            return fromAddress;

        } catch (final ScriptException x) {
            System.out.println(x.getMessage());
        }
    }

    return null;
}
</code></pre>

<p>(Note I used the variable names <code>pubKey</code> and <code>pubKeyHash</code> here, but in the case of P2SH these will instead be a script and a script hash. This method could also cause problems if the output being referenced is a multisig, P2PK, or something non-standard.)</p>

<p>I also notice your method only returns the first sender address. If a transaction has inputs from multiple sources, it might be worth returning a list or a set of those sender addresses. Just a thought.</p>

<p>Hope this helps!</p>
