Use P2SH Multisig instead of classic MS

This commit is contained in:
Manfred Karrer 2015-03-17 20:43:59 +01:00
parent b10b6ff203
commit 700c58071c
3 changed files with 35 additions and 19 deletions

View file

@ -239,7 +239,7 @@ public class TradeWalletService {
} }
// Add MultiSig output // Add MultiSig output
Script multiSigOutputScript = getMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey); Script multiSigOutputScript = getP2SHMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey);
// Tx fee for deposit tx will be paid by offerer. // Tx fee for deposit tx will be paid by offerer.
TransactionOutput msOutput = new TransactionOutput(params, depositTx, msOutputAmount, multiSigOutputScript.getProgram()); TransactionOutput msOutput = new TransactionOutput(params, depositTx, msOutputAmount, multiSigOutputScript.getProgram());
depositTx.addOutput(msOutput); depositTx.addOutput(msOutput);
@ -293,7 +293,7 @@ public class TradeWalletService {
checkArgument(takerConnectedOutputsForAllInputs.size() > 0); checkArgument(takerConnectedOutputsForAllInputs.size() > 0);
// Check if takers Multisig script is identical to mine // Check if takers Multisig script is identical to mine
Script multiSigOutputScript = getMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey); Script multiSigOutputScript = getP2SHMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey);
if (!takersDepositTx.getOutput(0).getScriptPubKey().equals(multiSigOutputScript)) if (!takersDepositTx.getOutput(0).getScriptPubKey().equals(multiSigOutputScript))
throw new TransactionVerificationException("Takers multiSigOutputScript does not match to my multiSigOutputScript"); throw new TransactionVerificationException("Takers multiSigOutputScript does not match to my multiSigOutputScript");
@ -373,14 +373,15 @@ public class TradeWalletService {
Coin offererPayoutAmount, Coin offererPayoutAmount,
Coin takerPayoutAmount, Coin takerPayoutAmount,
String takerAddressString, String takerAddressString,
AddressEntry addressEntry) AddressEntry addressEntry,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey)
throws AddressFormatException, TransactionVerificationException { throws AddressFormatException, TransactionVerificationException {
Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, addressEntry.getAddressString(), takerAddressString); Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, addressEntry.getAddressString(), takerAddressString);
// We need MS script not the P2SH
TransactionInput input = payoutTx.getInput(0); Script multiSigScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
TransactionOutput multiSigOutput = input.getConnectedOutput();
Script multiSigScript = multiSigOutput.getScriptPubKey();
Sha256Hash sigHash = payoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false); Sha256Hash sigHash = payoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = addressEntry.getKeyPair().sign(sigHash); ECKey.ECDSASignature offererSignature = addressEntry.getKeyPair().sign(sigHash);
@ -395,25 +396,27 @@ public class TradeWalletService {
Coin takerPayoutAmount, Coin takerPayoutAmount,
String offererAddressString, String offererAddressString,
AddressEntry addressEntry, AddressEntry addressEntry,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) FutureCallback<Transaction> callback)
throws AddressFormatException, TransactionVerificationException, WalletException { throws AddressFormatException, TransactionVerificationException, WalletException {
Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, offererAddressString, addressEntry.getAddressString()); Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, offererAddressString, addressEntry.getAddressString());
// We need MS script not the P2SH
TransactionInput input = payoutTx.getInput(0); Script multiSigScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
TransactionOutput multiSigOutput = input.getConnectedOutput();
Script multiSigScript = multiSigOutput.getScriptPubKey();
Sha256Hash sigHash = payoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false); Sha256Hash sigHash = payoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature takerSignature = addressEntry.getKeyPair().sign(sigHash); ECKey.ECDSASignature takerSignature = addressEntry.getKeyPair().sign(sigHash);
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false); TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
TransactionSignature offererTxSig = new TransactionSignature(offererSignature, Transaction.SigHash.ALL, false); TransactionSignature offererTxSig = new TransactionSignature(offererSignature, Transaction.SigHash.ALL, false);
Script inputScript = ScriptBuilder.createMultiSigInputScript(ImmutableList.of(offererTxSig, takerTxSig)); Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(offererTxSig, takerTxSig), multiSigScript);
TransactionInput input = payoutTx.getInput(0);
input.setScriptSig(inputScript); input.setScriptSig(inputScript);
verifyTransaction(payoutTx); verifyTransaction(payoutTx);
checkWalletConsistency(); checkWalletConsistency();
checkScriptSig(payoutTx, input, 0); checkScriptSig(payoutTx, input, 0);
input.verify(multiSigOutput); input.verify(input.getConnectedOutput());
printTxWithInputs("payoutTx", payoutTx); printTxWithInputs("payoutTx", payoutTx);
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(payoutTx); ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(payoutTx);
@ -424,13 +427,20 @@ public class TradeWalletService {
// Private methods // Private methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private Script getMultiSigOutputScript(byte[] offererPubKey, byte[] takerPubKey, byte[] arbitratorPubKey) { private Script getP2SHMultiSigOutputScript(byte[] offererPubKey, byte[] takerPubKey, byte[] arbitratorPubKey) {
ECKey offererKey = ECKey.fromPublicOnly(offererPubKey); ECKey offererKey = ECKey.fromPublicOnly(offererPubKey);
ECKey takerKey = ECKey.fromPublicOnly(takerPubKey); ECKey takerKey = ECKey.fromPublicOnly(takerPubKey);
ECKey arbitratorKey = ECKey.fromPublicOnly(arbitratorPubKey); ECKey arbitratorKey = ECKey.fromPublicOnly(arbitratorPubKey);
List<ECKey> keys = ImmutableList.of(offererKey, takerKey, arbitratorKey); List<ECKey> keys = ImmutableList.of(offererKey, takerKey, arbitratorKey);
return ScriptBuilder.createMultiSigOutputScript(2, keys); return ScriptBuilder.createP2SHOutputScript(2, keys);
}
private Script getMultiSigRedeemScript(byte[] offererPubKey, byte[] takerPubKey, byte[] arbitratorPubKey) {
ECKey offererKey = ECKey.fromPublicOnly(offererPubKey);
ECKey takerKey = ECKey.fromPublicOnly(takerPubKey);
ECKey arbitratorKey = ECKey.fromPublicOnly(arbitratorPubKey);
List<ECKey> keys = ImmutableList.of(offererKey, takerKey, arbitratorKey);
return ScriptBuilder.createRedeemScript(2, keys);
} }
private Transaction createPayoutTx(Transaction depositTx, Coin offererPayoutAmount, Coin takerPayoutAmount, private Transaction createPayoutTx(Transaction depositTx, Coin offererPayoutAmount, Coin takerPayoutAmount,

View file

@ -18,10 +18,10 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.TradeWalletService; import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.common.taskrunner.Task; import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -48,7 +48,10 @@ public class SignPayoutTx extends Task<BuyerAsOffererModel> {
offererPayoutAmount, offererPayoutAmount,
takerPayoutAmount, takerPayoutAmount,
model.getTakerPayoutAddress(), model.getTakerPayoutAddress(),
model.getWalletService().getAddressEntry(trade.getId())); model.getWalletService().getAddressEntry(trade.getId()),
model.getOffererPubKey(),
model.getTakerPubKey(),
model.getArbitratorPubKey());
model.setOffererPayoutTx(result.getPayoutTx()); model.setOffererPayoutTx(result.getPayoutTx());
model.setOffererSignature(result.getOffererSignature()); model.setOffererSignature(result.getOffererSignature());

View file

@ -48,6 +48,9 @@ public class SignAndPublishPayoutTx extends Task<SellerAsTakerModel> {
model.getTakerPayoutAmount(), model.getTakerPayoutAmount(),
model.getOffererPayoutAddress(), model.getOffererPayoutAddress(),
model.getAddressEntry(), model.getAddressEntry(),
model.getOffererPubKey(),
model.getTakerPubKey(),
model.getArbitratorPubKey(),
new FutureCallback<Transaction>() { new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {