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

Segwit for the trade protocol #4612

Merged
merged 10 commits into from
Nov 5, 2020

Conversation

oscarguindzberg
Copy link
Contributor

@oscarguindzberg oscarguindzberg commented Oct 9, 2020

Use segwit for trade protocol transactions.

@oscarguindzberg oscarguindzberg changed the base branch from release/v1.4.0 to master October 21, 2020 18:59
@@ -957,7 +1013,15 @@ public Transaction traderSignAndFinalizeDisputedPayoutTx(byte[] depositTxSeriali

// take care of sorting!
Script redeemScript = get2of3MultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
Sha256Hash sigHash;
boolean hashedMultiSigOutputIsSegwit = !ScriptPattern.isP2SH(hashedMultiSigOutput.getScriptPubKey());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to use "hashedMultiSigOutputIsLegacy" to avoid the 2x negation. Makes it easier to read...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

// Since there is no way to check migration to bitcoinj 0.15,
// Config.SEGWIT_TRADE_PROTOCOL_ACTIVE could be checked instead.
// Actually, given the serialized tx is used just as the connected tx of an input,
// we don't need the the connected tx's witness data.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate "the the"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the input always from the users own wallet (not the peers input)? If so I don't understand the above comment. Then this code is only execute anyway if the user runs the new version and segwit could be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate "the the"

fixed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the input always from the users own wallet (not the peers input)? If so I don't understand the above comment. Then this code is only execute anyway if the user runs the new version and segwit could be used.

When creating the deposit tx, traders will have a tx with an input from her wallet and an input from the counterparty. Traders collaborate creating the deposit tx. They send RawTransactionInput over p2p. So, if you are trading with a node that was not upgraded to bitcoinj 0.15 and RawTransactionInput.parentTransaction is serialized with segwit data, the other node won't be able to parse RawTransactionInput.parentTransaction correctly.
Extra comments:

  • RawTransactionInput.parentTransaction could be replaced with RawTransactionInput.parentTransactionHash since the tx is only used to obtain its hash.
  • Since we upgraded the trade protocol version, it is not possible to take a trade from a not-upgraded node, but better be on the safe side. This comment made probably more sense for the previous release.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will update the comment to make it more clear.

// VERSION = 0.5.0 -> TRADE_PROTOCOL_VERSION = 1
// Version 1.2.2 -> TRADE_PROTOCOL_VERSION = 2
public static final int TRADE_PROTOCOL_VERSION = 2;
// Version 1.4.1 -> TRADE_PROTOCOL_VERSION = 3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will be on 1.4.2 or more likely 1.5.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

if (scriptProgram.length == 0) {
throw new TransactionVerificationException("Inputs from maker not signed.");
}

return scriptProgram;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable is redundant now. Also does not throw exception anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all started with scriptProgram.length == 0 being valid for a segwit input.
I just removed the method and moved its content to where it was being used, i.e. takerSignsDepositTx().
See takerSignsDepositTx():

                byte[] makersScriptSigProgram = makersInput.getScriptSig().getProgram();
                if (makersScriptSigProgram.length == 0 && TransactionWitness.EMPTY.equals(makersInput.getWitness())) {
                    throw new TransactionVerificationException("Inputs from maker not signed.");
                }

See 7eb808d

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I saw. But now the method does not throw TransactionVerificationException anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw you removed the method. Good so...

Script scriptCode = new ScriptBuilder().data(
ScriptBuilder.createOutputScript(LegacyAddress.fromKey(transaction.getParams(), sigKey)).getProgram())
.build();
Script scriptCode = ScriptBuilder.createP2PKHOutputScript(sigKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is createP2PKHOutputScript correct? Would expect a segwit method...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is correct.
I know it sounds weird.
To sign a P2WPKH input you have to serialize the tx with a specific format, hash it and then sign the hash.
That specific format includes something called the scriptCode which should be: OP_DUP OP_HASH160 pubKeyHash OP_EQUALVERIFY OP_CHECKSIG. That is the same script format used in P2PKH outputs.
Detailed info: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Maybe a comment would be good with backgorund info.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

NetworkParameters params = btcWalletService.getParams();
Transaction preparedDepositTx = new Transaction(params, processModel.getPreparedDepositTx());
Coin delayedPayoutTxInputValue = preparedDepositTx.getOutput(0).getValue();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not take the input from preparedDelayedPayoutTx? If that is not possible, I would prefer to pass over the deposit tx to the signDelayedPayoutTx method and do the deail work in the TradeWalletService to keep the transaction domain more isolated there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In bitcoin (the protocol) inputs do not include the amount.
In bitcoinj (the library) you can connect a TransactionInput to its related TransactionOutput and then ask the TransactionInput its value. But it is only possible if you connected both of them.
I moved the code to obtain the input value to TradeWalletService.

@oscarguindzberg
Copy link
Contributor Author

I deleted Config.SEGWIT_TRADE_PROTOCOL_ACTIVE

@oscarguindzberg
Copy link
Contributor Author

@chimp1984 I addressed all your comments.

// Actually, given the serialized tx is used just as the connected tx of an input,
// we don't need the connected tx's witness data.
// bitcoinSerialize(false) is used just in case the serialized tx is parsed by a bisq node still using
// bitcoinj 0.14. The serialized tx is just used to obtain its hash, so the witness data is not relevant.
return new RawTransactionInput(input.getOutpoint().getIndex(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getRawInputFromTransactionInput is used only by methods for creating the deposit tx. With the trade protocol update we do not have mixed cases of segwit/legacy here. Or do I miss something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, you are right, just fixed the comment to explain that.

if (scriptProgram.length == 0) {
throw new TransactionVerificationException("Inputs from maker not signed.");
}

return scriptProgram;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw you removed the method. Good so...

@wiz
Copy link
Member

wiz commented Oct 22, 2020

is this ready to begin testing?

@chimp1984
Copy link
Contributor

chimp1984 commented Oct 22, 2020

@wiz Not really. You could test it locally but not with mainnet with real users....
We merge first all pending PRs to master, then create a release branch and merge segwit into it. Its a trade protocol update so master must not use that.

@oscarguindzberg
Copy link
Contributor Author

@wiz I suggest you wait until I remove the WIP tag.

chimp1984
chimp1984 previously approved these changes Oct 22, 2020
Copy link
Contributor

@chimp1984 chimp1984 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

@oscarguindzberg
Copy link
Contributor Author

I just squashed commits and polished commit messages, but I had not updated the codebase.

@oscarguindzberg oscarguindzberg changed the base branch from master to release/v1.5.0 November 5, 2020 14:49
@oscarguindzberg oscarguindzberg changed the title [WIP] Segwit for the trade protocol Segwit for the trade protocol Nov 5, 2020
@oscarguindzberg
Copy link
Contributor Author

  • WIP tag removed
  • Pointed PR to release/v1.5.0

Copy link
Contributor

@chimp1984 chimp1984 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

@ripcurlx ripcurlx merged commit 35018b0 into bisq-network:release/v1.5.0 Nov 5, 2020
@ripcurlx ripcurlx added this to the v1.5.0 milestone Nov 9, 2020
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

Successfully merging this pull request may close these issues.

4 participants