Refactor trade transactions

This commit is contained in:
Manfred Karrer 2015-03-15 23:46:46 +01:00
parent 2377db62fc
commit 6e3f83b8e0
33 changed files with 685 additions and 489 deletions

View File

@ -17,6 +17,9 @@
package io.bitsquare.btc;
import io.bitsquare.btc.exceptions.SigningException;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.btc.listeners.AddressConfidenceListener;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.listeners.TxConfidenceListener;
@ -31,7 +34,6 @@ import org.bitcoinj.core.DownloadListener;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.ScriptException;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
@ -87,6 +89,7 @@ import rx.Observable;
import rx.subjects.BehaviorSubject;
import rx.subjects.Subject;
import static com.google.inject.internal.util.$Preconditions.checkState;
import static org.bitcoinj.script.ScriptOpCodes.OP_RETURN;
public class WalletService {
@ -597,299 +600,219 @@ public class WalletService {
// Trade process
///////////////////////////////////////////////////////////////////////////////////////////
// 1. step: deposit tx
// Offerer creates the temporary 2of3 multiSig deposit tx with his unsigned input and change output
public Transaction offererPreparesDepositTx(Coin offererInputAmount,
String tradeId,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey) throws InsufficientMoneyException {
log.debug("offererCreatesMSTxAndAddPayment");
log.trace("inputs: ");
log.trace("offererInputAmount=" + offererInputAmount.toFriendlyString());
log.trace("offererPubKey=" + offererPubKey);
log.trace("takerPubKey=" + takerPubKey);
log.trace("arbitratorPubKey=" + arbitratorPubKey);
log.trace("tradeId=" + tradeId);
// 1. step: Define offerers inputs and outputs for the deposit tx
public TransactionDataResult offererCreatesDepositTxInputs(Coin inputAmount, AddressEntry addressInfo) throws InsufficientMoneyException,
TransactionVerificationException, WalletException {
// We need to subtract the fee as it will go to the miners
Coin offererInput = offererInputAmount.subtract(FeePolicy.TX_FEE);
log.trace("amountToPay=" + offererInput.toFriendlyString());
// We pay the tx fee 2 times to the deposit tx:
// 1. Will be spent when publishing the deposit tx (paid by offerer)
// 2. Will be added to the MS amount, so when publishing the payout tx the fee is already there and the outputs are not changed by fee reduction
// The fee for the payout will be paid by the taker.
// We pay the offererInputAmount to a temporary MS output which will be changed later to the correct value.
// With the usage of completeTx() we get all the work done with fee calculation, validation and coin selection.
// Later with more customized coin selection we can use a custom CoinSelector implementation.
// We don't commit that tx to the wallet as it will be changed later and it's not signed yet.
// So it will not change the wallet balance.
// The btc tx fee will be included by the completeTx() call, so we don't need to add it manually.
Transaction tx = new Transaction(params);
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
tx.addOutput(offererInput, multiSigOutputScript); // that output is just a dummy for input calculation
// inputAmount includes the tx fee. So we subtract the fee to get the dummyOutputAmount.
Coin dummyOutputAmount = inputAmount.subtract(FeePolicy.TX_FEE);
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.shuffleOutputs = false;
AddressEntry addressEntry = getAddressInfo(tradeId);
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to
// wait for 1 confirmation)
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry, true);
sendRequest.changeAddress = addressEntry.getAddress();
wallet.completeTx(sendRequest);
Transaction dummyTX = new Transaction(params);
// The output is just used to get the right inputs and change outputs, so we use an anonymous ECKey, as it will never be used for anything.
// We don't care about fee calculation differences between the real tx and that dummy tx as we use a static tx fee.
TransactionOutput msOutput = new TransactionOutput(params, dummyTX, dummyOutputAmount, new ECKey());
dummyTX.addOutput(msOutput);
// The completeTx() call signs the input, but we don't want to pass over a signed tx so we remove the
// signature to make sure the tx is invalid for publishing
// We have exactly 1 input as our spending transaction output is from the create offer fee payment and has only 1 output
tx.getInputs().get(0).setScriptSig(new Script(new byte[]{}));
// Fin the needed inputs to pay the output, optional add change output.
// Normally only 1 input and no change output is used, but we support multiple inputs and outputs. Our spending transaction output is from the create
// offer fee payment. In future changes (in case of no offer fee) multiple inputs might become used.
addAvailableInputsAndChangeOutputs(dummyTX, addressInfo);
log.trace("verify tx");
tx.verify();
// The completeTx() call signs the input, but we don't want to pass over signed tx inputs
// But to be safe and to support future changes (in case of no offer fee) we handle potential multiple inputs
removeSignatures(dummyTX);
verifyTransaction(dummyTX);
checkWalletConsistency();
// The created tx looks like:
/*
IN[0] any input > offererInputAmount + fee (unsigned)
OUT[0] MS offererInputAmount
OUT[1] Optional Change = input - offererInputAmount - fee btc tx fee
IN[0] any input > inputAmount (including tx fee) (unsigned)
IN[1...n] optional inputs supported, but currently there is just 1 input (unsigned)
OUT[0] dummyOutputAmount (inputAmount - tx fee)
OUT[1] Optional Change = inputAmount - dummyOutputAmount - tx fee
OUT[2...n] optional more outputs are supported, but currently there is just max. 1 optional change output
*/
log.trace("Check if wallet is consistent: result=" + wallet.isConsistent());
printInputs("offererCreatesMSTxAndAddPayment", tx);
log.debug("tx = " + tx);
printInputs("dummyTX", dummyTX);
log.debug("dummyTX created: " + dummyTX);
return tx;
List<TransactionOutput> connectedOutputsForAllInputs = new ArrayList<>();
for (TransactionInput input : dummyTX.getInputs()) {
connectedOutputsForAllInputs.add(input.getConnectedOutput());
}
// Only save offerer outputs, the MS output is ignored
List<TransactionOutput> outputs = new ArrayList<>();
for (TransactionOutput output : dummyTX.getOutputs()) {
if (output.equals(msOutput))
continue;
outputs.add(output);
}
return new TransactionDataResult(connectedOutputsForAllInputs, outputs);
}
// 2. step: deposit tx
// Taker adds his input and change output, changes the multiSig amount to the correct value and sign his input
public Transaction takerAddPaymentAndSignTx(Coin takerInputAmount,
Coin msOutputAmount,
Transaction preparedDepositTx,
String tradeId,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey) throws InsufficientMoneyException {
log.debug("takerAddPaymentAndSignTx");
log.trace("inputs: ");
log.trace("takerInputAmount=" + takerInputAmount.toFriendlyString());
log.trace("msOutputAmount=" + msOutputAmount.toFriendlyString());
log.trace("offererPubKey=" + offererPubKey);
log.trace("takerPubKey=" + takerPubKey);
log.trace("arbitratorPubKey=" + arbitratorPubKey);
log.trace("preparedDepositTransaction=" + preparedDepositTx);
log.trace("tradeId=" + tradeId);
// 2. step: Taker creates a deposit tx and signs his inputs
public TransactionDataResult takerCreatesAndSignsDepositTx(Coin inputAmount,
Coin msOutputAmount,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs,
AddressEntry addressInfo,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey) throws InsufficientMoneyException, SigningException,
TransactionVerificationException, WalletException {
// We pay the btc tx fee 2 times to the deposit tx:
// 1. will be spent to miners when publishing the deposit tx
// 2. will be as added to the MS amount, so when spending the payout tx the fee is already there and the
// outputs are not changed by fee reduction
// Both traders pay 1 times a fee, so it is equally split between them
// TODO verify amounts, addresses, MS
Transaction depositTx = new Transaction(params);
Script multiSigOutputScript = getMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey);
// We use temporary inputAmount as the value for the output amount to get the correct inputs from the takers side.
// Later when we add the offerer inputs we replace the output amount with the real msOutputAmount
// Tx fee for deposit tx will be paid by offerer.
TransactionOutput msOutput = new TransactionOutput(params, depositTx, inputAmount, multiSigOutputScript.getProgram());
depositTx.addOutput(msOutput);
// We do exactly the same as in the 1. step but with the takers input.
Transaction tempTx = new Transaction(params);
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
tempTx.addOutput(takerInputAmount, multiSigOutputScript);
// Not lets find the inputs to satisfy that output and add an optional change output
addAvailableInputsAndChangeOutputs(depositTx, addressInfo);
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tempTx);
sendRequest.shuffleOutputs = false;
AddressEntry addressEntry = getAddressInfo(tradeId);
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to
// wait for 1 confirmation)
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry, true);
sendRequest.changeAddress = addressEntry.getAddress();
wallet.completeTx(sendRequest);
// Now as we have the takers inputs and outputs we replace the temporary output amount with the real msOutputAmount
msOutput.setValue(msOutputAmount);
printInputs("tempTx", tempTx);
log.trace("tempTx=" + tempTx);
// That tx has signed input, but we don't need to remove it as we don't send that tx out,
// it is just used temporary.
// The created tempTx looks like:
/*
IN[0] any input taker > takerInputAmount + fee (signed)
OUT[0] MS takerInputAmount
OUT[1] Optional change = input taker - takerInputAmount - fee btc tx fee
*/
// Now we construct the real 2of3 multiSig tx from the serialized offerers tx
// The serialized offerers tx looks like:
/*
IN[0] any input offerer > offererInputAmount + fee (unsigned)
OUT[0] MS offererInputAmount
OUT[1] Change = input offerer - offererInputAmount - fee
btc tx fee
*/
// Now we add the inputs and outputs from our temp tx and change the multiSig amount to the correct value
for (TransactionInput input : tempTx.getInputs()) {
preparedDepositTx.addInput(input);
}
// handle optional change output
if (tempTx.getOutputs().size() == 2) {
preparedDepositTx.addOutput(tempTx.getOutput(1));
// Save reference to inputs for signing, before we add offerer inputs
List<TransactionInput> takerInputs = new ArrayList<>(depositTx.getInputs());
List<TransactionOutput> connectedOutputsForAllTakerInputs = new ArrayList<>();
for (TransactionInput input : takerInputs) {
connectedOutputsForAllTakerInputs.add(input.getConnectedOutput());
}
preparedDepositTx.getOutput(0).setValue(msOutputAmount);
// Now we sign our input (index 1)
TransactionInput input = preparedDepositTx.getInput(1);
if (input == null || input.getConnectedOutput() == null)
log.error("Must not happen - input or input.getConnectedOutput() is null: " + input);
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
Sha256Hash hash = preparedDepositTx.hashForSignature(1, scriptPubKey, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature ecSig = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey()) {
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
}
else if (scriptPubKey.isSentToAddress()) {
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
}
else {
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
// Lets save the takerOutputs for passing later to the result, the MS output is ignored
List<TransactionOutput> takerOutputs = new ArrayList<>();
for (TransactionOutput output : depositTx.getOutputs()) {
if (output.equals(msOutput))
continue;
takerOutputs.add(output);
}
log.trace("check if it can be correctly spent for input 1");
input.getScriptSig().correctlySpends(preparedDepositTx, 1, scriptPubKey);
// Add all inputs from offerer (normally its just 1 input)
for (TransactionOutput connectedOutputForInput : offererConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
TransactionInput transactionInput = new TransactionInput(params, depositTx, new byte[]{}, outPoint);
depositTx.addInput(transactionInput);
}
log.trace("verify tx");
preparedDepositTx.verify();
// Add optional outputs
for (TransactionOutput output : offererOutputs) {
depositTx.addOutput(output);
}
// The resulting tx looks like:
/*
IN[0] any input offerer > offererInputAmount + fee (unsigned) e.g.: 0.1001
IN[1] any input taker > takerInputAmount + fee (signed) e.g.: 1.1001
OUT[0] MS offererInputAmount e.g.: 1.2001
OUT[1] Change = input offerer - offererInputAmount - fee e.g.: 0 if input is matching correct value
OUT[2] Change = input taker - takerInputAmount - fee e.g.: 0 if input is matching correct value btc tx fee e.g.: 0.1001
*/
printInputs("depositTx", depositTx);
log.debug("depositTx = " + depositTx);
// We must not commit that tx to the wallet as we will get it over the network when the offerer
// publishes it and it will have a different tx hash, so it would invalidate our wallet.
// Sign taker inputs
// Taker inputs are the first inputs (0 -n), so the index of takerInputs and depositTx.getInputs() matches for the number of takerInputs.
int index = 0;
for (TransactionInput input : takerInputs) {
log.debug("signInput input "+input.toString());
log.debug("signInput index "+index);
signInput(depositTx, input, index);
checkScriptSig(depositTx, input, index);
index++;
}
log.trace("Check if wallet is consistent before commit: result=" + wallet.isConsistent());
printInputs("takerAddPaymentAndSignTx", preparedDepositTx);
log.debug("tx = " + preparedDepositTx);
return preparedDepositTx;
verifyTransaction(depositTx);
checkWalletConsistency();
printInputs("depositTx", depositTx);
log.debug("depositTx = " + depositTx);
return new TransactionDataResult(depositTx, connectedOutputsForAllTakerInputs, takerOutputs);
}
// 3. step: deposit tx
// Offerer signs tx and publishes it
public void offererSignAndPublishTx(Transaction preparedDepositTx,
Transaction takersSignedDepositTx,
Transaction takersFromTx,
byte[] takersSignedScriptSig,
long offererTxOutIndex,
long takerTxOutIndex,
FutureCallback<Transaction> callback) {
log.debug("offererSignAndPublishTx");
log.trace("inputs: ");
log.trace("preparedDepositTx=" + preparedDepositTx);
log.trace("takersSignedTx=" + takersSignedDepositTx);
log.trace("takersFromTx=" + takersFromTx);
log.trace("takersSignedScriptSig=" + takersSignedScriptSig);
log.trace("callback=" + callback);
public void offererSignAndPublishTx(Transaction takersDepositTx,
List<TransactionOutput> takersConnectedOutputsForAllInputs,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException, WalletException {
// We create an empty tx (did not find a way to manipulate a tx input, otherwise the takers tx could be used
// directly and add the offerers input and output)
Transaction tx = new Transaction(params);
// TODO verify amounts, addresses, MS
// The outpoints are not available from the serialized takersDepositTx, so we cannot use that tx directly, but we use it to construct a new depositTx
Transaction depositTx = new Transaction(params);
printInputs("preparedDepositTx", preparedDepositTx);
log.trace("preparedDepositTx = " + preparedDepositTx);
// We save offererInputs for later signing when tx is fully constructed
List<TransactionInput> offererInputs = new ArrayList<>();
// add input
Transaction offerersFirstTxConnOut = wallet.getTransaction(preparedDepositTx.getInput(0).getOutpoint().getHash());
TransactionOutPoint offerersFirstTxOutPoint = new TransactionOutPoint(params, offererTxOutIndex, offerersFirstTxConnOut);
TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, new byte[]{}, offerersFirstTxOutPoint);
offerersFirstTxInput.setParent(tx);
tx.addInput(offerersFirstTxInput);
printInputs("takersSignedTxInput", takersSignedDepositTx);
log.trace("takersSignedTx = " + takersSignedDepositTx);
// add input
TransactionOutPoint takersSignedTxOutPoint = new TransactionOutPoint(params, takerTxOutIndex, takersFromTx);
TransactionInput takersSignedTxInput = new TransactionInput(
params, tx, takersSignedScriptSig, takersSignedTxOutPoint);
takersSignedTxInput.setParent(tx);
tx.addInput(takersSignedTxInput);
// add outputs from takers tx, they are already correct
tx.addOutput(takersSignedDepositTx.getOutput(0));
if (takersSignedDepositTx.getOutputs().size() > 1) {
tx.addOutput(takersSignedDepositTx.getOutput(1));
}
if (takersSignedDepositTx.getOutputs().size() == 3) {
tx.addOutput(takersSignedDepositTx.getOutput(2));
// Add all inputs from offerer (normally its just 1 input)
for (TransactionOutput connectedOutputForInput : offererConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
TransactionInput input = new TransactionInput(params, depositTx, new byte[]{}, outPoint);
offererInputs.add(input);
depositTx.addInput(input);
}
printInputs("tx", tx);
log.trace("tx = " + tx);
log.trace("Wallet balance before signing: " + wallet.getBalance());
// Add all inputs from taker and apply signature
for (TransactionOutput connectedOutputForInput : takersConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
// sign the input
TransactionInput input = tx.getInput(0);
if (input == null || input.getConnectedOutput() == null) {
log.error("input or input.getConnectedOutput() is null: " + input);
// We grab the signatures from the takersDepositTx and apply it to the new tx input
Optional<TransactionInput> result = takersDepositTx.getInputs().stream()
.filter(e -> e.getConnectedOutput().hashCode() == connectedOutputForInput.hashCode()).findAny();
if (result.isPresent()) {
TransactionInput signedInput = result.get();
Script script = signedInput.getScriptSig();
TransactionInput transactionInput = new TransactionInput(params, depositTx, script.getProgram(), outPoint);
depositTx.addInput(transactionInput);
}
}
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
Sha256Hash hash = tx.hashForSignature(0, scriptPubKey, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature ecSig = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey()) {
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
}
else if (scriptPubKey.isSentToAddress()) {
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
}
else {
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
// Add all outputs from takersDepositTx to depositTx
takersDepositTx.getOutputs().forEach(depositTx::addOutput);
printInputs("depositTx", depositTx);
log.debug("depositTx = " + depositTx);
// Offerer inputs are the first inputs (0 -n), so the index of offererInputs and depositTx.getInputs() matches for the number of offererInputs.
int index = 0;
for (TransactionInput input : offererInputs) {
signInput(depositTx, input, index);
checkScriptSig(depositTx, input, index);
index++;
}
input.getScriptSig().correctlySpends(tx, 0, scriptPubKey);
log.trace("check if it can be correctly spent for input 0 OK");
TransactionInput input1 = tx.getInput(1);
scriptPubKey = input1.getConnectedOutput().getScriptPubKey();
input1.getScriptSig().correctlySpends(tx, 1, scriptPubKey);
log.trace("check if it can be correctly spent for input 1 OK");
/*
IN[0] offerer signed 0.1001
IN[1] taker signed 1.1001
OUT[0] MS (include btc tx fee for payout tx) 1.2001
OUT[1] offerer change
OUT[2] taker change
btc tx fee 0.0001
*/
log.trace("verify ");
tx.verify();
printInputs("tx", tx);
log.debug("tx = " + tx);
// TODO verify MS, amounts
//Script multiSigOutputScript = getMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey);
verifyTransaction(depositTx);
checkWalletConsistency();
// Broadcast depositTx
log.trace("Wallet balance before broadcastTransaction: " + wallet.getBalance());
log.trace("Check if wallet is consistent before broadcastTransaction: result=" + wallet.isConsistent());
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx);
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(depositTx);
log.trace("Wallet balance after broadcastTransaction: " + wallet.getBalance());
log.trace("Check if wallet is consistent: result=" + wallet.isConsistent());
log.trace("Check if wallet is consistent after broadcastTransaction: result=" + wallet.isConsistent());
Futures.addCallback(broadcastComplete, callback);
printInputs("tx", tx);
log.debug("tx = " + tx);
}
// 4 step deposit tx: Offerer send deposit tx to taker
public Transaction takerCommitDepositTx(Transaction depositTx) {
public Transaction takerCommitDepositTx(Transaction depositTx) throws WalletException {
log.trace("takerCommitDepositTx");
log.trace("inputs: ");
log.trace("depositTx=" + depositTx);
// If not recreate the tx we get a null pointer at receivePending
depositTx = new Transaction(params, depositTx.bitcoinSerialize());
//depositTx = new Transaction(params, depositTx.bitcoinSerialize());
log.trace("depositTx=" + depositTx);
// boolean isAlreadyInWallet = wallet.maybeCommitTx(depositTx);
//log.trace("isAlreadyInWallet=" + isAlreadyInWallet);
@ -900,6 +823,8 @@ public class WalletService {
wallet.receivePending(depositTx, null, true);
} catch (Throwable t) {
log.error(t.getMessage());
t.printStackTrace();
throw new WalletException(t);
}
return depositTx;
@ -1008,7 +933,7 @@ public class WalletService {
}
}
private Script getMultiSigScript(byte[] offererPubKey, byte[] takerPubKey, byte[] arbitratorPubKey) {
private Script getMultiSigOutputScript(byte[] offererPubKey, byte[] takerPubKey, byte[] arbitratorPubKey) {
ECKey offererKey = ECKey.fromPublicOnly(offererPubKey);
ECKey takerKey = ECKey.fromPublicOnly(takerPubKey);
ECKey arbitratorKey = ECKey.fromPublicOnly(arbitratorPubKey);
@ -1049,12 +974,120 @@ public class WalletService {
}
}
private void checkWalletConsistency() throws WalletException {
try {
log.trace("Check if wallet is consistent before commit.");
checkState(wallet.isConsistent());
} catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
throw new WalletException(t);
}
}
private void verifyTransaction(Transaction transaction) throws TransactionVerificationException {
try {
log.trace("Verify transaction");
transaction.verify();
} catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
throw new TransactionVerificationException(t);
}
}
private void signInput(Transaction transaction, TransactionInput input, int inputIndex) throws SigningException, TransactionVerificationException {
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
Sha256Hash hash = transaction.hashForSignature(inputIndex, scriptPubKey, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature signature = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(signature, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey()) {
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
}
else if (scriptPubKey.isSentToAddress()) {
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
}
else {
throw new SigningException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
}
}
private void checkScriptSig(Transaction transaction, TransactionInput input, int inputIndex) throws TransactionVerificationException {
try {
log.trace("Verifies that this script (interpreted as a scriptSig) correctly spends the given scriptPubKey.");
input.getScriptSig().correctlySpends(transaction, inputIndex, input.getConnectedOutput().getScriptPubKey());
inputIndex++;
} catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
throw new TransactionVerificationException(t);
}
}
/* private void checkScriptSigForAllInputs(Transaction transaction) throws TransactionVerificationException {
int inputIndex = 0;
for (TransactionInput input : transaction.getInputs()) {
checkScriptSig(transaction, input, inputIndex);
}
}*/
private void removeSignatures(Transaction transaction) throws InsufficientMoneyException {
for (TransactionInput input : transaction.getInputs()) {
input.setScriptSig(new Script(new byte[]{}));
}
}
private void addAvailableInputsAndChangeOutputs(Transaction transaction, AddressEntry addressEntry) throws InsufficientMoneyException {
// Lets let the framework do the work to find the right inputs
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(transaction);
sendRequest.shuffleOutputs = false;
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation)
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry, true);
sendRequest.changeAddress = addressEntry.getAddress();
// With the usage of completeTx() we get all the work done with fee calculation, validation and coin selection.
// We don't commit that tx to the wallet as it will be changed later and it's not signed yet.
// So it will not change the wallet balance.
wallet.completeTx(sendRequest);
printInputs("transaction", transaction);
log.trace("transaction=" + transaction);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Inner classes
///////////////////////////////////////////////////////////////////////////////////////////
public class TransactionDataResult {
private final List<TransactionOutput> connectedOutputsForAllInputs;
private final List<TransactionOutput> outputs;
private Transaction depositTx;
public TransactionDataResult(List<TransactionOutput> connectedOutputsForAllInputs, List<TransactionOutput> outputs) {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
this.outputs = outputs;
}
public TransactionDataResult(Transaction depositTx, List<TransactionOutput> connectedOutputsForAllInputs, List<TransactionOutput> outputs) {
this.depositTx = depositTx;
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
this.outputs = outputs;
}
public List<TransactionOutput> getOutputs() {
return outputs;
}
public List<TransactionOutput> getConnectedOutputsForAllInputs() {
return connectedOutputsForAllInputs;
}
public Transaction getDepositTx() {
return depositTx;
}
}
private static class ObservableDownloadListener extends DownloadListener {
private final Subject<Double, Double> subject = BehaviorSubject.create(0d);

View File

@ -0,0 +1,34 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.exceptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SigningException extends Exception {
private static final Logger log = LoggerFactory.getLogger(SigningException.class);
public SigningException(String message) {
super(message);
}
public SigningException(Throwable t) {
super(t);
}
}

View File

@ -0,0 +1,29 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.exceptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TransactionVerificationException extends Exception {
private static final Logger log = LoggerFactory.getLogger(TransactionVerificationException.class);
public TransactionVerificationException(Throwable t) {
super(t);
}
}

View File

@ -0,0 +1,29 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.exceptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WalletException extends Exception {
private static final Logger log = LoggerFactory.getLogger(WalletException.class);
public WalletException(Throwable t) {
super(t);
}
}

View File

@ -26,7 +26,7 @@ import io.bitsquare.trade.protocol.placeoffer.tasks.BroadcastCreateOfferFeeTx;
import io.bitsquare.trade.protocol.placeoffer.tasks.CreateOfferFeeTx;
import io.bitsquare.trade.protocol.placeoffer.tasks.ValidateOffer;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.tasks.PrepareDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestTakeOfferMessage;
@ -43,7 +43,7 @@ import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.PayDeposit;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.PayTakeOfferFee;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
@ -51,7 +51,7 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRespondToTakeOfferRe
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTxAsHex;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
@ -110,7 +110,7 @@ public class DebugView extends InitializableView {
RespondToTakeOfferRequest.class,
ProcessTakeOfferFeePayedMessage.class,
PrepareDepositTx.class,
GetOffererDepositTxInputs.class,
RequestDepositPayment.class,
ProcessRequestOffererPublishDepositTxMessage.class,
@ -140,8 +140,8 @@ public class DebugView extends InitializableView {
ProcessRequestDepositPaymentMessage.class,
VerifyOffererAccount.class,
CreateAndSignContract.class,
PayDeposit.class,
SendSignedTakerDepositTxAsHex.class,
TakerCreatesAndSignsDepositTx.class,
SendSignedTakerDepositTx.class,
ProcessDepositTxPublishedMessage.class,
TakerCommitDepositTx.class,

View File

@ -18,6 +18,7 @@
package io.bitsquare.trade.protocol.trade;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
@ -50,6 +51,9 @@ public class OfferSharedModel extends SharedModel {
protected final ECKey accountKey;
protected final byte[] arbitratorPubKey;
// lazy initialized at first read access, as we don't want to create an entry before it is really needed
protected AddressEntry addressInfo;
// data written/read by tasks
protected TradeMessage tradeMessage;
protected byte[] takerPubKey;
@ -77,6 +81,28 @@ public class OfferSharedModel extends SharedModel {
}
// getter/setter
public AddressEntry getAddressInfo() {
if (addressInfo == null)
addressInfo = getWalletService().getAddressInfo(offer.getId());
return addressInfo;
}
public String getPeersAccountId() {
return peersAccountId;
}
public void setPeersAccountId(String peersAccountId) {
this.peersAccountId = peersAccountId;
}
public BankAccount getPeersBankAccount() {
return peersBankAccount;
}
public void setPeersBankAccount(BankAccount peersBankAccount) {
this.peersBankAccount = peersBankAccount;
}
public TradeMessageService getTradeMessageService() {
return tradeMessageService;

View File

@ -31,9 +31,12 @@ import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import java.security.PublicKey;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -52,28 +55,25 @@ public class BuyerAsOffererModel extends OfferSharedModel {
private Trade trade;
private Peer taker;
private Transaction preparedDepositTx;
private Transaction depositTx;
private String takerAccountId;
private BankAccount takerBankAccount;
private PublicKey takerMessagePublicKey;
private String takerContractAsJson;
private Transaction takersSignedDepositTx;
private Transaction takersFromTx;
private byte[] txScriptSig;
private long takerTxOutIndex;
private Coin takerPaybackAmount;
private String takeOfferFeeTxId;
private String takerPayoutAddress;
private long offererTxOutIndex;
private byte[] offererPubKey;
private ECKey.ECDSASignature offererSignature;
private Coin offererPaybackAmount;
private List<TransactionOutput> offererConnectedOutputsForAllInputs;
private List<TransactionOutput> offererOutputs;
private Transaction takerDepositTx;
private List<TransactionOutput> takerConnectedOutputsForAllInputs;
private List<TransactionOutput> takerOutputs;
private String takerPayoutAddress;
private Transaction offererPayoutTx;
private Transaction publishedDepositTx;
///////////////////////////////////////////////////////////////////////////////////////////
@ -110,21 +110,6 @@ public class BuyerAsOffererModel extends OfferSharedModel {
return offererPaybackAddress;
}
public Transaction getPreparedDepositTx() {
return preparedDepositTx;
}
public void setPreparedDepositTx(Transaction preparedDepositTx) {
this.preparedDepositTx = preparedDepositTx;
}
public long getOffererTxOutIndex() {
return offererTxOutIndex;
}
public void setOffererTxOutIndex(long offererTxOutIndex) {
this.offererTxOutIndex = offererTxOutIndex;
}
public String getTakeOfferFeeTxId() {
return takeOfferFeeTxId;
@ -134,14 +119,6 @@ public class BuyerAsOffererModel extends OfferSharedModel {
this.takeOfferFeeTxId = takeOfferFeeTxId;
}
public String getTakerPayoutAddress() {
return takerPayoutAddress;
}
public void setTakerPayoutAddress(String takerPayoutAddress) {
this.takerPayoutAddress = takerPayoutAddress;
}
@Override
public String getTakerAccountId() {
return takerAccountId;
@ -178,37 +155,6 @@ public class BuyerAsOffererModel extends OfferSharedModel {
this.takerContractAsJson = takerContractAsJson;
}
public Transaction getTakersSignedDepositTx() {
return takersSignedDepositTx;
}
public void setTakersSignedDepositTx(Transaction takersSignedDepositTx) {
this.takersSignedDepositTx = takersSignedDepositTx;
}
public Transaction getTakersFromTx() {
return takersFromTx;
}
public void setTakersFromTx(Transaction takersFromTx) {
this.takersFromTx = takersFromTx;
}
public byte[] getTxScriptSig() {
return txScriptSig;
}
public void setTxScriptSig(byte[] txScriptSig) {
this.txScriptSig = txScriptSig;
}
public long getTakerTxOutIndex() {
return takerTxOutIndex;
}
public void setTakerTxOutIndex(long takerTxOutIndex) {
this.takerTxOutIndex = takerTxOutIndex;
}
public byte[] getOffererPubKey() {
return offererPubKey;
@ -218,13 +164,6 @@ public class BuyerAsOffererModel extends OfferSharedModel {
this.offererPubKey = offererPubKey;
}
public Transaction getDepositTx() {
return depositTx;
}
public void setDepositTx(Transaction depositTx) {
this.depositTx = depositTx;
}
public ECKey.ECDSASignature getOffererSignature() {
return offererSignature;
@ -261,4 +200,68 @@ public class BuyerAsOffererModel extends OfferSharedModel {
public void setTaker(Peer taker) {
this.taker = taker;
}
public List<TransactionOutput> getOffererConnectedOutputsForAllInputs() {
return offererConnectedOutputsForAllInputs;
}
public void setOffererConnectedOutputsForAllInputs(List<TransactionOutput> offererConnectedOutputsForAllInputs) {
this.offererConnectedOutputsForAllInputs = offererConnectedOutputsForAllInputs;
}
public List<TransactionOutput> getOffererOutputs() {
return offererOutputs;
}
public void setOffererOutputs(List<TransactionOutput> offererOutputs) {
this.offererOutputs = offererOutputs;
}
public void setTakerDepositTx(Transaction takerDepositTx) {
this.takerDepositTx = takerDepositTx;
}
public Transaction getTakerDepositTx() {
return takerDepositTx;
}
public void setTakerConnectedOutputsForAllInputs(List<TransactionOutput> takerConnectedOutputsForAllInputs) {
this.takerConnectedOutputsForAllInputs = takerConnectedOutputsForAllInputs;
}
public List<TransactionOutput> getTakerConnectedOutputsForAllInputs() {
return takerConnectedOutputsForAllInputs;
}
public void setTakerOutputs(List<TransactionOutput> takerOutputs) {
this.takerOutputs = takerOutputs;
}
public List<TransactionOutput> getTakerOutputs() {
return takerOutputs;
}
public String getTakerPayoutAddress() {
return takerPayoutAddress;
}
public void setTakerPayoutAddress(String takerPayoutAddress) {
this.takerPayoutAddress = takerPayoutAddress;
}
public void setOffererPayoutTx(Transaction offererPayoutTx) {
this.offererPayoutTx = offererPayoutTx;
}
public Transaction getOffererPayoutTx() {
return offererPayoutTx;
}
public void setPublishedDepositTx(Transaction publishedDepositTx) {
this.publishedDepositTx = publishedDepositTx;
}
public Transaction getPublishedDepositTx() {
return publishedDepositTx;
}
}

View File

@ -21,7 +21,7 @@ import io.bitsquare.network.Message;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.handlers.MessageHandler;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.PrepareDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestTakeOfferMessage;
@ -110,7 +110,7 @@ public class BuyerAsOffererProtocol {
);
taskRunner.addTasks(
ProcessTakeOfferFeePayedMessage.class,
PrepareDepositTx.class,
GetOffererDepositTxInputs.class,
RequestDepositPayment.class
);
taskRunner.run();

View File

@ -20,29 +20,34 @@ package io.bitsquare.trade.protocol.trade.offerer.messages;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import java.io.Serializable;
import java.util.List;
public class RequestDepositPaymentMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = -3988720410493712913L;
private final String tradeId;
private final List<TransactionOutput> offererConnectedOutputsForAllInputs;
private final List<TransactionOutput> offererOutputs;
private final byte[] offererPubKey;
private final BankAccount bankAccount;
private final String accountID;
private final byte[] offererPubKey;
private final Transaction preparedDepositTx;
private final long offererTxOutIndex;
public RequestDepositPaymentMessage(String tradeId, BankAccount bankAccount, String accountID,
byte[] offererPubKey, Transaction preparedDepositTx,
long offererTxOutIndex) {
public RequestDepositPaymentMessage(String tradeId,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs,
byte[] offererPubKey,
BankAccount bankAccount,
String accountID) {
this.tradeId = tradeId;
this.offererConnectedOutputsForAllInputs = offererConnectedOutputsForAllInputs;
this.offererOutputs = offererOutputs;
this.offererPubKey = offererPubKey;
this.bankAccount = bankAccount;
this.accountID = accountID;
this.offererPubKey = offererPubKey;
this.preparedDepositTx = preparedDepositTx;
this.offererTxOutIndex = offererTxOutIndex;
}
@Override
@ -50,6 +55,18 @@ public class RequestDepositPaymentMessage implements Serializable, TradeMessage
return tradeId;
}
public List<TransactionOutput> getOffererConnectedOutputsForAllInputs() {
return offererConnectedOutputsForAllInputs;
}
public List<TransactionOutput> getOffererOutputs() {
return offererOutputs;
}
public byte[] getOffererPubKey() {
return offererPubKey;
}
public BankAccount getBankAccount() {
return bankAccount;
}
@ -57,16 +74,4 @@ public class RequestDepositPaymentMessage implements Serializable, TradeMessage
public String getAccountId() {
return accountID;
}
public byte[] getOffererPubKey() {
return offererPubKey;
}
public Transaction getPreparedDepositTx() {
return preparedDepositTx;
}
public long getOffererTxOutIndex() {
return offererTxOutIndex;
}
}

View File

@ -17,45 +17,37 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.taskrunner.Task;
import io.bitsquare.util.taskrunner.TaskRunner;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PrepareDepositTx extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(PrepareDepositTx.class);
public class GetOffererDepositTxInputs extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(GetOffererDepositTxInputs.class);
public PrepareDepositTx(TaskRunner taskHandler, BuyerAsOffererModel model) {
public GetOffererDepositTxInputs(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
byte[] offererPubKey = model.getWalletService().getAddressInfo(model.getTrade().getId()).getPubKey();
Coin offererInputAmount = model.getTrade().getSecurityDeposit().add(FeePolicy.TX_FEE);
Transaction transaction = model.getWalletService().offererPreparesDepositTx(
offererInputAmount,
model.getTrade().getId(),
offererPubKey,
model.getTakerPubKey(),
model.getArbitratorPubKey());
long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex();
model.setOffererPubKey(offererPubKey);
model.setPreparedDepositTx(transaction);
model.setOffererTxOutIndex(offererTxOutIndex);
AddressEntry addressInfo = model.getWalletService().getAddressInfo(model.getTrade().getId());
WalletService.TransactionDataResult result = model.getWalletService().offererCreatesDepositTxInputs(offererInputAmount, addressInfo);
model.setOffererConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
model.setOffererOutputs(result.getOutputs());
complete();
} catch (InsufficientMoneyException e) {
} catch (Throwable e) {
failed(e);
}
}

View File

@ -25,7 +25,7 @@ import io.bitsquare.util.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOffererModel> {
@ -39,17 +39,16 @@ public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOf
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
RequestOffererPublishDepositTxMessage message = (RequestOffererPublishDepositTxMessage) model.getTradeMessage();
model.setTakerPayoutAddress(nonEmptyStringOf(message.getTakerPayoutAddress()));
model.setTakerAccountId(nonEmptyStringOf(message.getTakerAccountId()));
model.setTakerBankAccount(checkNotNull(message.getTakerBankAccount()));
model.setTakerAccountId(nonEmptyStringOf(message.getTakerAccountId()));
model.setTakerMessagePublicKey(checkNotNull(message.getTakerMessagePublicKey()));
model.setTakerContractAsJson(nonEmptyStringOf(message.getTakerContractAsJson()));
model.setTakersSignedDepositTx(checkNotNull(message.getTakersSignedDepositTx()));
model.setTakersFromTx(checkNotNull(message.getTakersFromTx()));
model.setTxScriptSig(checkNotNull(message.getTxScriptSig()));
model.setTakerTxOutIndex(nonNegativeLongOf(message.getTakerTxOutIndex()));
model.setTakerDepositTx(checkNotNull(message.getTakersDepositTx()));
model.setTakerConnectedOutputsForAllInputs(checkNotNull(message.getTakersConnectedOutputsForAllInputs()));
checkArgument(message.getTakersConnectedOutputsForAllInputs().size() > 0);
model.setTakerOutputs(checkNotNull(message.getTakerOutputs()));
complete();
} catch (Throwable t) {

View File

@ -36,9 +36,6 @@ public class ProcessRequestTakeOfferMessage extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
try {
log.debug("######### " + model.getOffer().getId());
log.debug("######### " + model.getTradeMessage().getTradeId());
checkTradeId(model.getOffer().getId(), model.getTradeMessage());
complete();

View File

@ -40,7 +40,6 @@ public class ProcessTakeOfferFeePayedMessage extends Task<BuyerAsOffererModel> {
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
Trade trade = model.getTrade();
TakeOfferFeePayedMessage takeOfferFeePayedMessage = (TakeOfferFeePayedMessage) model.getTradeMessage();
trade.setTakeOfferFeeTxID(nonEmptyStringOf(takeOfferFeePayedMessage.getTakeOfferFeeTxId()));

View File

@ -35,13 +35,14 @@ public class RequestDepositPayment extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
byte[] offererPubKey = model.getWalletService().getAddressInfo(model.getTrade().getId()).getPubKey();
RequestDepositPaymentMessage tradeMessage = new RequestDepositPaymentMessage(
model.getTrade().getId(),
model.getOffererConnectedOutputsForAllInputs(),
model.getOffererOutputs(),
offererPubKey,
model.getBankAccount(),
model.getAccountId(),
model.getOffererPubKey(),
model.getPreparedDepositTx(),
model.getOffererTxOutIndex());
model.getAccountId());
model.getTradeMessageService().sendMessage(model.getTaker(), tradeMessage, new SendMessageListener() {
@Override

View File

@ -39,7 +39,7 @@ public class RespondToTakeOfferRequest extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
offerIsAvailable = model.getOpenOffer().getState() == OpenOffer.State.OPEN;
if (offerIsAvailable) {
Trade trade = new Trade(model.getOpenOffer().getOffer());
model.setTrade(trade);

View File

@ -37,7 +37,7 @@ public class SendBankTransferStartedMessage extends Task<BuyerAsOffererModel> {
protected void doRun() {
BankTransferStartedMessage tradeMessage = new BankTransferStartedMessage(
model.getTrade().getId(),
model.getDepositTx(),
model.getPublishedDepositTx(),
model.getOffererSignature().encodeToDER(),
model.getOffererPaybackAmount(),
model.getTakerPaybackAmount(),

View File

@ -35,8 +35,7 @@ public class SendDepositTxIdToTaker extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(model.getTrade().getId(),
model.getTrade().getDepositTx());
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(model.getTrade().getId(), model.getTrade().getDepositTx());
model.getTradeMessageService().sendMessage(model.getTaker(), tradeMessage, new SendMessageListener() {
@Override

View File

@ -42,17 +42,18 @@ public class SignAndPublishDepositTx extends Task<BuyerAsOffererModel> {
protected void doRun() {
try {
model.getWalletService().offererSignAndPublishTx(
model.getPreparedDepositTx(),
model.getTakersSignedDepositTx(),
model.getTakersFromTx(),
model.getTxScriptSig(),
model.getOffererTxOutIndex(),
model.getTakerTxOutIndex(),
model.getTakerDepositTx(),
model.getTakerConnectedOutputsForAllInputs(),
model.getOffererConnectedOutputsForAllInputs(),
model.getOffererPubKey(),
model.getTakerPubKey(),
model.getArbitratorPubKey(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("offererSignAndPublishTx succeeded " + transaction);
model.setPublishedDepositTx(transaction);
model.getTrade().setDepositTx(transaction);
model.getTrade().setState(Trade.State.DEPOSIT_PUBLISHED);

View File

@ -53,7 +53,7 @@ public class SignPayoutTx extends Task<BuyerAsOffererModel> {
model.getTakerPayoutAddress(),
model.getTrade().getId());
model.setDepositTx(result.getValue());
model.setOffererPayoutTx(result.getValue());
model.setOffererSignature(result.getKey());
model.setOffererPaybackAmount(offererPaybackAmount);
model.setTakerPaybackAmount(takerPaybackAmount);

View File

@ -29,6 +29,9 @@ import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -38,6 +41,7 @@ public class SellerAsTakerModel extends OfferSharedModel {
// provided
private final Trade trade;
// written/read by task
private Peer offerer;
@ -52,6 +56,12 @@ public class SellerAsTakerModel extends OfferSharedModel {
private ECKey.ECDSASignature offererSignature;
private Coin offererPaybackAmount;
private String offererPayoutAddress;
private List<TransactionOutput> offererConnectedOutputsForAllInputs;
private List<TransactionOutput> offererOutputs;
private List<TransactionOutput> takerConnectedOutputsForAllInputs;
private List<TransactionOutput> takerOutputs;
private Transaction takerDepositTx;
private Transaction publishedDepositTx;
public SellerAsTakerModel(Trade trade,
TradeMessageService tradeMessageService,
@ -68,9 +78,29 @@ public class SellerAsTakerModel extends OfferSharedModel {
this.trade = trade;
takerPubKey = walletService.getAddressInfo(trade.getId()).getPubKey();
}
// getter/setter
public void setOffererPubKey(byte[] offererPubKey) {
this.offererPubKey = offererPubKey;
}
public List<TransactionOutput> getOffererConnectedOutputsForAllInputs() {
return offererConnectedOutputsForAllInputs;
}
public void setOffererConnectedOutputsForAllInputs(List<TransactionOutput> offererConnectedOutputsForAllInputs) {
this.offererConnectedOutputsForAllInputs = offererConnectedOutputsForAllInputs;
}
public List<TransactionOutput> getOffererOutputs() {
return offererOutputs;
}
public void setOffererOutputs(List<TransactionOutput> offererOutputs) {
this.offererOutputs = offererOutputs;
}
public Trade getTrade() {
return trade;
}
@ -103,9 +133,6 @@ public class SellerAsTakerModel extends OfferSharedModel {
return offererPubKey;
}
public void setOffererPubKeyAsHex(byte[] offererPubKey) {
this.offererPubKey = offererPubKey;
}
public Transaction getPreparedDepositTx() {
return preparedDepositTx;
@ -172,4 +199,35 @@ public class SellerAsTakerModel extends OfferSharedModel {
}
public void setTakerConnectedOutputsForAllInputs(List<TransactionOutput> takerConnectedOutputsForAllInputs) {
this.takerConnectedOutputsForAllInputs = takerConnectedOutputsForAllInputs;
}
public List<TransactionOutput> getTakerConnectedOutputsForAllInputs() {
return takerConnectedOutputsForAllInputs;
}
public void setTakerOutputs(List<TransactionOutput> takerOutputs) {
this.takerOutputs = takerOutputs;
}
public List<TransactionOutput> getTakerOutputs() {
return takerOutputs;
}
public void setTakerDepositTx(Transaction takerDepositTx) {
this.takerDepositTx = takerDepositTx;
}
public Transaction getTakerDepositTx() {
return takerDepositTx;
}
public void setPublishedDepositTx(Transaction publishedDepositTx) {
this.publishedDepositTx = publishedDepositTx;
}
public Transaction getPublishedDepositTx() {
return publishedDepositTx;
}
}

View File

@ -28,7 +28,7 @@ import io.bitsquare.trade.protocol.trade.offerer.messages.RequestDepositPaymentM
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.GetPeerAddress;
import io.bitsquare.trade.protocol.trade.taker.tasks.PayDeposit;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.PayTakeOfferFee;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
@ -36,7 +36,7 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymen
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTxAsHex;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
@ -129,8 +129,8 @@ public class SellerAsTakerProtocol {
ProcessRequestDepositPaymentMessage.class,
VerifyOffererAccount.class,
CreateAndSignContract.class,
PayDeposit.class,
SendSignedTakerDepositTxAsHex.class
TakerCreatesAndSignsDepositTx.class,
SendSignedTakerDepositTx.class
);
taskRunner.run();
}

View File

@ -21,53 +21,44 @@ import io.bitsquare.bank.BankAccount;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import java.io.Serializable;
import java.security.PublicKey;
import java.util.List;
public class RequestOffererPublishDepositTxMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = 2179683654379803071L;
private final String tradeId;
private final BankAccount bankAccount;
private final String accountID;
private final PublicKey takerMessagePublicKey;
private final Transaction takersSignedDepositTx;
private final byte[] txScriptSig;
private final Transaction takersFromTx;
private final String contractAsJson;
private final String takerContractSignature;
private final String takerPayoutAddress;
private final long takerTxOutIndex;
private final long offererTxOutIndex;
private Transaction takersDepositTx;
private List<TransactionOutput> takersConnectedOutputsForAllInputs;
private List<TransactionOutput> takerOutputs;
public RequestOffererPublishDepositTxMessage(String tradeId,
BankAccount bankAccount,
String accountID,
PublicKey takerMessagePublicKey,
Transaction takersSignedDepositTx,
byte[] txScriptSig,
Transaction takersFromTx,
String contractAsJson,
String takerContractSignature,
String takerPayoutAddress,
long takerTxOutIndex,
long offererTxOutIndex) {
Transaction takersDepositTx,
List<TransactionOutput> takersConnectedOutputsForAllInputs,
List<TransactionOutput> takerOutputs) {
this.tradeId = tradeId;
this.bankAccount = bankAccount;
this.accountID = accountID;
this.takerMessagePublicKey = takerMessagePublicKey;
this.takersSignedDepositTx = takersSignedDepositTx;
this.txScriptSig = txScriptSig;
this.takersFromTx = takersFromTx;
this.contractAsJson = contractAsJson;
this.takerContractSignature = takerContractSignature;
this.takerPayoutAddress = takerPayoutAddress;
this.takerTxOutIndex = takerTxOutIndex;
this.offererTxOutIndex = offererTxOutIndex;
this.takersDepositTx = takersDepositTx;
this.takersConnectedOutputsForAllInputs = takersConnectedOutputsForAllInputs;
this.takerOutputs = takerOutputs;
}
@ -76,10 +67,6 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return tradeId;
}
public long getOffererTxOutIndex() {
return offererTxOutIndex;
}
public BankAccount getTakerBankAccount() {
return bankAccount;
}
@ -92,18 +79,6 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return takerMessagePublicKey;
}
public Transaction getTakersSignedDepositTx() {
return takersSignedDepositTx;
}
public byte[] getTxScriptSig() {
return txScriptSig;
}
public Transaction getTakersFromTx() {
return takersFromTx;
}
public String getTakerContractAsJson() {
return contractAsJson;
}
@ -112,12 +87,27 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return takerContractSignature;
}
public String getTakerPayoutAddress() {
return takerPayoutAddress;
public List<TransactionOutput> getTakerOutputs() {
return takerOutputs;
}
public long getTakerTxOutIndex() {
return takerTxOutIndex;
public BankAccount getBankAccount() {
return bankAccount;
}
public String getAccountID() {
return accountID;
}
public String getContractAsJson() {
return contractAsJson;
}
public Transaction getTakersDepositTx() {
return takersDepositTx;
}
public List<TransactionOutput> getTakersConnectedOutputsForAllInputs() {
return takersConnectedOutputsForAllInputs;
}
}

View File

@ -43,13 +43,12 @@ public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel>
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
BankTransferStartedMessage message = (BankTransferStartedMessage) model.getTradeMessage();
model.setDepositTx(checkNotNull(message.getDepositTx()));
//model.setDepositTx(checkNotNull(message.getDepositTx()));
model.setOffererSignature(checkNotNull(ECKey.ECDSASignature.decodeFromDER(message.getOffererSignature())));
model.setOffererPaybackAmount(positiveCoinOf(nonZeroCoinOf(message.getOffererPaybackAmount())));
model.setTakerPaybackAmount(positiveCoinOf(nonZeroCoinOf(message.getTakerPaybackAmount())));
model.setOffererPayoutAddress(nonEmptyStringOf(message.getOffererPayoutAddress()));
// TODO listener.onBankTransferInited(message.getTrade().getId());
complete();
} catch (Throwable t) {
failed(t);

View File

@ -41,7 +41,7 @@ public class ProcessDepositTxPublishedMessage extends Task<SellerAsTakerModel> {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
DepositTxPublishedMessage message = (DepositTxPublishedMessage) model.getTradeMessage();
model.setDepositTx(checkNotNull(message.getDepositTx()));
model.setPublishedDepositTx(checkNotNull(message.getDepositTx()));
complete();
} catch (Throwable t) {

View File

@ -25,7 +25,7 @@ import io.bitsquare.util.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class ProcessRequestDepositPaymentMessage extends Task<SellerAsTakerModel> {
@ -40,11 +40,13 @@ public class ProcessRequestDepositPaymentMessage extends Task<SellerAsTakerModel
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
RequestDepositPaymentMessage message = (RequestDepositPaymentMessage) model.getTradeMessage();
model.setTakerAccountId(nonEmptyStringOf(message.getAccountId()));
model.setOffererConnectedOutputsForAllInputs(checkNotNull(message.getOffererConnectedOutputsForAllInputs()));
checkArgument(message.getOffererConnectedOutputsForAllInputs().size() > 0);
model.setOffererOutputs(checkNotNull(message.getOffererOutputs()));
model.setOffererPubKey(checkNotNull(message.getOffererPubKey()));
model.setTakerBankAccount(checkNotNull(message.getBankAccount()));
model.setOffererPubKeyAsHex(checkNotNull(message.getOffererPubKey()));
model.setPreparedDepositTx(checkNotNull(message.getPreparedDepositTx()));
model.setOffererTxOutIndex(nonNegativeLongOf(message.getOffererTxOutIndex()));
model.setTakerAccountId(nonEmptyStringOf(message.getAccountId()));
complete();
} catch (Throwable t) {

View File

@ -36,7 +36,6 @@ public class RequestTakeOffer extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
log.debug("######### " + model.getTrade().getId());
model.getTradeMessageService().sendMessage(model.getOfferer(), new RequestTakeOfferMessage(model.getTrade().getId()),
new SendMessageListener() {
@Override

View File

@ -23,36 +23,29 @@ import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDep
import io.bitsquare.util.taskrunner.Task;
import io.bitsquare.util.taskrunner.TaskRunner;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendSignedTakerDepositTxAsHex extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
public class SendSignedTakerDepositTx extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTx.class);
public SendSignedTakerDepositTxAsHex(TaskRunner taskHandler, SellerAsTakerModel model) {
public SendSignedTakerDepositTx(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
Transaction takersSignedDepositTx = model.getSignedTakerDepositTx();
long takerTxOutIndex = model.getSignedTakerDepositTx().getInput(1).getOutpoint().getIndex();
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(
model.getTrade().getId(),
model.getBankAccount(),
model.getAccountId(),
model.getMessagePublicKey(),
takersSignedDepositTx,
takersSignedDepositTx.getInput(1).getScriptBytes(),
takersSignedDepositTx.getInput(1).getConnectedOutput().getParentTransaction(),
model.getTrade().getContractAsJson(),
model.getTrade().getTakerContractSignature(),
model.getWalletService().getAddressInfo(model.getTrade().getId()).getAddressString(),
takerTxOutIndex,
model.getOffererTxOutIndex());
model.getTakerDepositTx(),
model.getTakerConnectedOutputsForAllInputs(),
model.getTakerOutputs()
);
model.getTradeMessageService().sendMessage(model.getOfferer(), tradeMessage, new SendMessageListener() {
@Override

View File

@ -43,7 +43,7 @@ public class SignAndPublishPayoutTx extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
try {
model.getWalletService().takerSignsAndSendsTx(model.getDepositTx(),
model.getWalletService().takerSignsAndSendsTx(model.getPublishedDepositTx(),
model.getOffererSignature(),
model.getOffererPaybackAmount(),
model.getTakerPaybackAmount(),

View File

@ -37,7 +37,7 @@ public class TakerCommitDepositTx extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
try {
Transaction transaction = model.getWalletService().takerCommitDepositTx(model.getDepositTx());
Transaction transaction = model.getWalletService().takerCommitDepositTx(model.getPublishedDepositTx());
model.getTrade().setDepositTx(transaction);
model.getTrade().setState(Trade.State.DEPOSIT_PUBLISHED);

View File

@ -18,42 +18,46 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.taskrunner.Task;
import io.bitsquare.util.taskrunner.TaskRunner;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayDeposit extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
public class TakerCreatesAndSignsDepositTx extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignsDepositTx.class);
public PayDeposit(TaskRunner taskHandler, SellerAsTakerModel model) {
public TakerCreatesAndSignsDepositTx(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
Coin amountToPay = model.getTrade().getTradeAmount().add(model.getTrade().getSecurityDeposit());
Coin msOutputAmount = amountToPay.add(model.getTrade().getSecurityDeposit()).add(FeePolicy.TX_FEE);
Transaction signedTakerDepositTx = model.getWalletService().takerAddPaymentAndSignTx(
amountToPay,
Coin inputAmount = model.getTrade().getTradeAmount().add(model.getTrade().getSecurityDeposit());
Coin msOutputAmount = inputAmount.add(model.getTrade().getSecurityDeposit()).add(FeePolicy.TX_FEE);
WalletService.TransactionDataResult result = model.getWalletService().takerCreatesAndSignsDepositTx(
inputAmount,
msOutputAmount,
model.getPreparedDepositTx(),
model.getTrade().getId(),
model.getOffererConnectedOutputsForAllInputs(),
model.getOffererOutputs(),
model.getAddressInfo(),
model.getOffererPubKey(),
model.getTakerPubKey(),
model.getArbitratorPubKey());
model.setSignedTakerDepositTx(signedTakerDepositTx);
model.setTakerConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
model.setTakerOutputs(result.getOutputs());
model.setTakerDepositTx(result.getDepositTx());
complete();
} catch (InsufficientMoneyException e) {
} catch (Exception e) {
failed(e);
}
}

View File

@ -51,7 +51,6 @@ import org.slf4j.LoggerFactory;
* The TomP2P library codebase shall not be used outside that service.
* That way we limit the dependency of the TomP2P library only to that class (and it's sub components).
* <p/>
* TODO: improve callbacks that executor.execute is not necessary. We call usually that methods form teh UI thread.
*/
public class TomP2PTradeMessageService implements TradeMessageService {
private static final Logger log = LoggerFactory.getLogger(TomP2PTradeMessageService.class);

View File

@ -17,6 +17,10 @@
package io.bitsquare.util.taskrunner;
import io.bitsquare.btc.exceptions.SigningException;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -45,7 +49,7 @@ public abstract class Task<T extends SharedModel> {
}
}
abstract protected void doRun();
abstract protected void doRun() throws WalletException, TransactionVerificationException, SigningException;
abstract protected void updateStateOnFault();

View File

@ -38,16 +38,17 @@
<logger name="net.tomp2p" level="ERROR"/>
<logger name="com.vinumeris.updatefx" level="OFF"/>
<logger name="io.netty" level="OFF"/>
<logger name="org.bitcoinj.core.BitcoinSerializer" level="ERROR"/>
<logger name="org.bitcoinj.core.Peer" level="ERROR"/>
<!-- <logger name="net.tomp2p.message.Encoder" level="WARN"/>
<logger name="net.tomp2p.message.Decoder" level="WARN"/>
<logger name="net.tomp2p.message.MessageHeaderCodec" level="WARN"/>
<logger name="io.netty.util" level="WARN"/>
<logger name="io.netty.channel" level="WARN"/>
<logger name="io.netty.buffer" level="WARN"/>-->
<!-- <logger name="net.tomp2p.message.Encoder" level="WARN"/>
<logger name="net.tomp2p.message.Decoder" level="WARN"/>
<logger name="net.tomp2p.message.MessageHeaderCodec" level="WARN"/>
<logger name="io.netty.util" level="WARN"/>
<logger name="io.netty.channel" level="WARN"/>
<logger name="io.netty.buffer" level="WARN"/>-->