refactoring trade protocol, reformatting

This commit is contained in:
Manfred Karrer 2014-07-05 15:37:34 +02:00
parent cb4ca6b2a7
commit fd1f23ea62
95 changed files with 2207 additions and 2621 deletions

13
pom.xml
View file

@ -198,17 +198,10 @@
--> -->
<dependency> <dependency>
<groupId>com.typesafe.akka</groupId> <groupId>org.jetbrains</groupId>
<artifactId>akka-actor_2.11</artifactId> <artifactId>annotations</artifactId>
<version>2.3.3</version> <version>13.0</version>
</dependency> </dependency>
<!--
<dependency>
<groupId>com.netflix.rxjava</groupId>
<artifactId>rxjava-core</artifactId>
<version>0.5.3</version>
</dependency>
-->
</dependencies> </dependencies>
<reporting> <reporting>

View file

@ -36,7 +36,9 @@ public class BitSquare extends Application
{ {
log.debug("Startup: main"); log.debug("Startup: main");
if (args != null && args.length > 0) if (args != null && args.length > 0)
{
ID = args[0]; ID = args[0];
}
launch(args); launch(args);
} }
@ -73,9 +75,13 @@ public class BitSquare extends Application
settings.updateFromStorage((Settings) storage.read(settings.getClass().getName())); settings.updateFromStorage((Settings) storage.read(settings.getClass().getName()));
if (ID.isEmpty()) if (ID.isEmpty())
{
stage.setTitle("BitSquare"); stage.setTitle("BitSquare");
}
else else
{
stage.setTitle("BitSquare (" + ID + ")"); stage.setTitle("BitSquare (" + ID + ")");
}
GuiceFXMLLoader.setInjector(injector); GuiceFXMLLoader.setInjector(injector);
@ -101,9 +107,11 @@ public class BitSquare extends Application
stage.show(); stage.show();
Action response = Popups.openExceptionPopup(e); Action response = Popups.openExceptionPopup(e);
if (response == Dialog.Actions.OK) if (response == Dialog.Actions.OK)
{
Platform.exit(); Platform.exit();
} }
} }
}
@Override @Override
public void stop() throws Exception public void stop() throws Exception

View file

@ -16,10 +16,14 @@ class RelayNode
public static void main(String[] args) throws Exception public static void main(String[] args) throws Exception
{ {
if (args != null && args.length == 1) if (args != null && args.length == 1)
{
INSTANCE(new Integer(args[0])); INSTANCE(new Integer(args[0]));
}
else else
{
INSTANCE(5000); INSTANCE(5000);
} }
}
private static void INSTANCE(int port) throws Exception private static void INSTANCE(int port) throws Exception
{ {

View file

@ -26,13 +26,7 @@ public class BankAccount implements Serializable
private final String accountTitle; private final String accountTitle;
public BankAccount(BankAccountType bankAccountType, public BankAccount(BankAccountType bankAccountType, Currency currency, Country country, String accountTitle, String accountHolderName, String accountPrimaryID, String accountSecondaryID)
Currency currency,
Country country,
String accountTitle,
String accountHolderName,
String accountPrimaryID,
String accountSecondaryID)
{ {
this.bankAccountType = bankAccountType; this.bankAccountType = bankAccountType;
this.currency = currency; this.currency = currency;
@ -53,9 +47,13 @@ public class BankAccount implements Serializable
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if (!(obj instanceof BankAccount)) if (!(obj instanceof BankAccount))
{
return false; return false;
}
if (obj == this) if (obj == this)
{
return true; return true;
}
final BankAccount other = (BankAccount) obj; final BankAccount other = (BankAccount) obj;
return uid.equals(other.getUid()); return uid.equals(other.getUid());

View file

@ -51,18 +51,28 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
TransactionConfidence conf1 = a.getParentTransaction().getConfidence(); TransactionConfidence conf1 = a.getParentTransaction().getConfidence();
TransactionConfidence conf2 = b.getParentTransaction().getConfidence(); TransactionConfidence conf2 = b.getParentTransaction().getConfidence();
if (conf1.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) if (conf1.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
depth1 = conf1.getDepthInBlocks(); depth1 = conf1.getDepthInBlocks();
}
if (conf2.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) if (conf2.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
depth2 = conf2.getDepthInBlocks(); depth2 = conf2.getDepthInBlocks();
}
BigInteger aValue = a.getValue(); BigInteger aValue = a.getValue();
BigInteger bValue = b.getValue(); BigInteger bValue = b.getValue();
BigInteger aCoinDepth = aValue.multiply(BigInteger.valueOf(depth1)); BigInteger aCoinDepth = aValue.multiply(BigInteger.valueOf(depth1));
BigInteger bCoinDepth = bValue.multiply(BigInteger.valueOf(depth2)); BigInteger bCoinDepth = bValue.multiply(BigInteger.valueOf(depth2));
int c1 = bCoinDepth.compareTo(aCoinDepth); int c1 = bCoinDepth.compareTo(aCoinDepth);
if (c1 != 0) return c1; if (c1 != 0)
{
return c1;
}
// The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size. // The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size.
int c2 = bValue.compareTo(aValue); int c2 = bValue.compareTo(aValue);
if (c2 != 0) return c2; if (c2 != 0)
{
return c2;
}
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering. // They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
BigInteger aHash = a.getParentTransaction().getHash().toBigInteger(); BigInteger aHash = a.getParentTransaction().getHash().toBigInteger();
BigInteger bHash = b.getParentTransaction().getHash().toBigInteger(); BigInteger bHash = b.getParentTransaction().getHash().toBigInteger();
@ -75,8 +85,7 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
// Pick chain-included transactions and transactions that are pending. // Pick chain-included transactions and transactions that are pending.
TransactionConfidence confidence = tx.getConfidence(); TransactionConfidence confidence = tx.getConfidence();
TransactionConfidence.ConfidenceType type = confidence.getConfidenceType(); TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) || return type.equals(TransactionConfidence.ConfidenceType.BUILDING) || type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
// In regtest mode we expect to have only one peer, so we won't see transactions propagate. // In regtest mode we expect to have only one peer, so we won't see transactions propagate.
// TODO: The value 1 below dates from a time when transactions we broadcast *to* were counted, set to 0 // TODO: The value 1 below dates from a time when transactions we broadcast *to* were counted, set to 0
(confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get()); (confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get());
@ -96,10 +105,14 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
protected boolean shouldSelect(Transaction tx) protected boolean shouldSelect(Transaction tx)
{ {
if (includePending) if (includePending)
{
return isInBlockChainOrPending(tx); return isInBlockChainOrPending(tx);
}
else else
{
return isInBlockChain(tx); return isInBlockChain(tx);
} }
}
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected boolean matchesRequiredAddress(TransactionOutput transactionOutput) protected boolean matchesRequiredAddress(TransactionOutput transactionOutput)
@ -134,11 +147,16 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
long total = 0; long total = 0;
for (TransactionOutput output : sortedOutputs) for (TransactionOutput output : sortedOutputs)
{ {
if (total >= target) break; if (total >= target)
{
break;
}
// Only pick chain-included transactions, or transactions that are ours and pending. // Only pick chain-included transactions, or transactions that are ours and pending.
// Only select outputs from our defined address(es) // Only select outputs from our defined address(es)
if (!shouldSelect(output.getParentTransaction()) || !matchesRequiredAddress(output)) if (!shouldSelect(output.getParentTransaction()) || !matchesRequiredAddress(output))
{
continue; continue;
}
selected.add(output); selected.add(output);
total += output.getValue().longValue(); total += output.getValue().longValue();

View file

@ -63,7 +63,9 @@ public class BitSquareWalletAppKit extends WalletAppKit
vPeerGroup.setBloomFilterFalsePositiveRate(0.001); // 0,1% instead of default 0,05% vPeerGroup.setBloomFilterFalsePositiveRate(0.001); // 0,1% instead of default 0,05%
if (this.userAgent != null) if (this.userAgent != null)
{
vPeerGroup.setUserAgent(userAgent, version); vPeerGroup.setUserAgent(userAgent, version);
}
if (vWalletFile.exists()) if (vWalletFile.exists())
{ {
walletStream = new FileInputStream(vWalletFile); walletStream = new FileInputStream(vWalletFile);
@ -71,20 +73,28 @@ public class BitSquareWalletAppKit extends WalletAppKit
addWalletExtensions(); // All extensions must be present before we deserialize addWalletExtensions(); // All extensions must be present before we deserialize
new WalletProtobufSerializer().readWallet(WalletProtobufSerializer.parseToProto(walletStream), vWallet); new WalletProtobufSerializer().readWallet(WalletProtobufSerializer.parseToProto(walletStream), vWallet);
if (shouldReplayWallet) if (shouldReplayWallet)
{
vWallet.clearTransactions(0); vWallet.clearTransactions(0);
} }
}
else else
{ {
vWallet = new BitSquareWallet(params); vWallet = new BitSquareWallet(params);
vWallet.addKey(new ECKey()); vWallet.addKey(new ECKey());
addWalletExtensions(); addWalletExtensions();
} }
if (useAutoSave) vWallet.autosaveToFile(vWalletFile, 1, TimeUnit.SECONDS, null); if (useAutoSave)
{
vWallet.autosaveToFile(vWalletFile, 1, TimeUnit.SECONDS, null);
}
// Set up peer addresses or discovery first, so if wallet extensions try to broadcast a transaction // Set up peer addresses or discovery first, so if wallet extensions try to broadcast a transaction
// before we're actually connected the broadcast waits for an appropriate number of connections. // before we're actually connected the broadcast waits for an appropriate number of connections.
if (peerAddresses != null) if (peerAddresses != null)
{ {
for (PeerAddress addr : peerAddresses) vPeerGroup.addAddress(addr); for (PeerAddress addr : peerAddresses)
{
vPeerGroup.addAddress(addr);
}
peerAddresses = null; peerAddresses = null;
} }
else else
@ -130,13 +140,18 @@ public class BitSquareWalletAppKit extends WalletAppKit
throw new IOException(e); throw new IOException(e);
} finally } finally
{ {
if (walletStream != null) walletStream.close(); if (walletStream != null)
{
walletStream.close();
}
} }
} }
private void installShutdownHook() private void installShutdownHook()
{ {
if (autoStop) Runtime.getRuntime().addShutdownHook(new Thread() if (autoStop)
{
Runtime.getRuntime().addShutdownHook(new Thread()
{ {
@Override @Override
public void run() public void run()
@ -154,3 +169,4 @@ public class BitSquareWalletAppKit extends WalletAppKit
}); });
} }
} }
}

View file

@ -124,7 +124,9 @@ public class WalletFacade
//walletAppKit.peerGroup().setMaxConnections(11); //walletAppKit.peerGroup().setMaxConnections(11);
if (params == RegTestParams.get()) if (params == RegTestParams.get())
{
walletAppKit.peerGroup().setMinBroadcastConnections(1); walletAppKit.peerGroup().setMinBroadcastConnections(1);
}
/* else /* else
walletAppKit.peerGroup().setMinBroadcastConnections(2); */ walletAppKit.peerGroup().setMinBroadcastConnections(2); */
@ -262,7 +264,9 @@ public class WalletFacade
{ {
AddressEntry arbitratorDepositAddressEntry = getAddressInfoByAddressContext(AddressEntry.AddressContext.ARBITRATOR_DEPOSIT); AddressEntry arbitratorDepositAddressEntry = getAddressInfoByAddressContext(AddressEntry.AddressContext.ARBITRATOR_DEPOSIT);
if (arbitratorDepositAddressEntry == null) if (arbitratorDepositAddressEntry == null)
{
arbitratorDepositAddressEntry = getNewArbitratorDepositAddressEntry(); arbitratorDepositAddressEntry = getNewArbitratorDepositAddressEntry();
}
return arbitratorDepositAddressEntry; return arbitratorDepositAddressEntry;
} }
@ -270,24 +274,38 @@ public class WalletFacade
AddressEntry getUnusedTradeAddressInfo() AddressEntry getUnusedTradeAddressInfo()
{ {
List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList), addressInfo -> (addressInfo != null && addressInfo.getAddressContext().equals(AddressEntry.AddressContext.TRADE) && addressInfo.getTradeId() == null))); List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList),
addressInfo -> (addressInfo != null && addressInfo.getAddressContext()
.equals(AddressEntry.AddressContext.TRADE) && addressInfo
.getTradeId() == null)));
if (filteredList != null && !filteredList.isEmpty()) if (filteredList != null && !filteredList.isEmpty())
{
return filteredList.get(0); return filteredList.get(0);
}
else else
{
return getNewTradeAddressEntry(); return getNewTradeAddressEntry();
} }
}
private AddressEntry getAddressInfoByAddressContext(AddressEntry.AddressContext addressContext) private AddressEntry getAddressInfoByAddressContext(AddressEntry.AddressContext addressContext)
{ {
List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList), addressInfo -> (addressInfo != null && addressInfo.getAddressContext() != null && addressInfo.getAddressContext().equals(addressContext)))); List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList),
addressInfo -> (addressInfo != null && addressInfo.getAddressContext() != null && addressInfo.getAddressContext()
.equals(addressContext)
)));
if (filteredList != null && !filteredList.isEmpty()) if (filteredList != null && !filteredList.isEmpty())
{
return filteredList.get(0); return filteredList.get(0);
}
else else
{
return null; return null;
} }
}
public AddressEntry getAddressInfoByTradeID(String tradeId) public AddressEntry getAddressInfoByTradeID(String tradeId)
@ -295,8 +313,10 @@ public class WalletFacade
for (AddressEntry addressEntry : ImmutableList.copyOf(addressEntryList)) for (AddressEntry addressEntry : ImmutableList.copyOf(addressEntryList))
{ {
if (addressEntry.getTradeId() != null && addressEntry.getTradeId().equals(tradeId)) if (addressEntry.getTradeId() != null && addressEntry.getTradeId().equals(tradeId))
{
return addressEntry; return addressEntry;
} }
}
AddressEntry addressEntry = getUnusedTradeAddressInfo(); AddressEntry addressEntry = getUnusedTradeAddressInfo();
assert addressEntry != null; assert addressEntry != null;
@ -343,8 +363,10 @@ public class WalletFacade
for (AddressEntry addressEntry : addressEntryList) for (AddressEntry addressEntry : addressEntryList)
{ {
if (addressEntry.getAddressString().equals(address)) if (addressEntry.getAddressString().equals(address))
{
return addressEntry; return addressEntry;
} }
}
return null; return null;
} }
@ -424,8 +446,10 @@ public class WalletFacade
{ {
TransactionOutput transactionOutput = transactionInput.getConnectedOutput(); TransactionOutput transactionOutput = transactionInput.getConnectedOutput();
if (transactionOutput != null) if (transactionOutput != null)
{
connectedOutputs.add(transactionOutput); connectedOutputs.add(transactionOutput);
} }
}
List<TransactionOutput> mergedOutputs = new ArrayList<>(); List<TransactionOutput> mergedOutputs = new ArrayList<>();
mergedOutputs.addAll(transactionOutputs); mergedOutputs.addAll(transactionOutputs);
@ -460,7 +484,9 @@ public class WalletFacade
{ {
TransactionConfidence transactionConfidence = null; TransactionConfidence transactionConfidence = null;
if (getRegistrationAddressInfo() != null) if (getRegistrationAddressInfo() != null)
{
transactionConfidence = getConfidenceForAddress(getRegistrationAddressInfo().getAddress()); transactionConfidence = getConfidenceForAddress(getRegistrationAddressInfo().getAddress());
}
return transactionConfidence != null && transactionConfidence.getConfidenceType().equals(TransactionConfidence.ConfidenceType.BUILDING); return transactionConfidence != null && transactionConfidence.getConfidenceType().equals(TransactionConfidence.ConfidenceType.BUILDING);
} }
@ -497,9 +523,13 @@ public class WalletFacade
{ {
BigInteger balance; BigInteger balance;
if (balanceListener.getAddress() != null) if (balanceListener.getAddress() != null)
{
balance = getBalanceForAddress(balanceListener.getAddress()); balance = getBalanceForAddress(balanceListener.getAddress());
}
else else
{
balance = getWalletBalance(); balance = getWalletBalance();
}
balanceListener.onBalanceChanged(balance); balanceListener.onBalanceChanged(balance);
} }
@ -667,7 +697,11 @@ public class WalletFacade
// 1. step: deposit tx // 1. step: deposit tx
// Offerer creates the 2of3 multiSig deposit tx with his unsigned input and change output // Offerer creates the 2of3 multiSig deposit tx with his unsigned input and change output
public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererInputAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey, String tradeId) throws InsufficientMoneyException public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererInputAmount,
String offererPubKey,
String takerPubKey,
String arbitratorPubKey,
String tradeId) throws InsufficientMoneyException
{ {
log.debug("offererCreatesMSTxAndAddPayment"); log.debug("offererCreatesMSTxAndAddPayment");
log.trace("inputs: "); log.trace("inputs: ");
@ -724,8 +758,7 @@ public class WalletFacade
String takerPubKey, String takerPubKey,
String arbitratorPubKey, String arbitratorPubKey,
String offerersPartialDepositTxAsHex, String offerersPartialDepositTxAsHex,
String tradeId String tradeId) throws InsufficientMoneyException
) throws InsufficientMoneyException
{ {
log.debug("takerAddPaymentAndSignTx"); log.debug("takerAddPaymentAndSignTx");
log.trace("inputs: "); log.trace("inputs: ");
@ -782,7 +815,9 @@ public class WalletFacade
// Now we add the inputs and outputs from our temp tx and change the multiSig amount to the correct value // Now we add the inputs and outputs from our temp tx and change the multiSig amount to the correct value
tx.addInput(tempTx.getInput(0)); tx.addInput(tempTx.getInput(0));
if (tempTx.getOutputs().size() == 2) if (tempTx.getOutputs().size() == 2)
{
tx.addOutput(tempTx.getOutput(1)); tx.addOutput(tempTx.getOutput(1));
}
// We add the btc tx fee to the msOutputAmount and apply the change to the multiSig output // We add the btc tx fee to the msOutputAmount and apply the change to the multiSig output
msOutputAmount = msOutputAmount.add(FeePolicy.TX_FEE); msOutputAmount = msOutputAmount.add(FeePolicy.TX_FEE);
@ -791,7 +826,9 @@ public class WalletFacade
// Now we sign our input // Now we sign our input
TransactionInput input = tx.getInput(1); TransactionInput input = tx.getInput(1);
if (input == null || input.getConnectedOutput() == null) if (input == null || input.getConnectedOutput() == null)
{
log.error("input or input.getConnectedOutput() is null: " + input); log.error("input or input.getConnectedOutput() is null: " + input);
}
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey(); Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet); ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
@ -799,11 +836,17 @@ public class WalletFacade
ECKey.ECDSASignature ecSig = sigKey.sign(hash); ECKey.ECDSASignature ecSig = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false); TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey()) if (scriptPubKey.isSentToRawPubKey())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig)); input.setScriptSig(ScriptBuilder.createInputScript(txSig));
}
else if (scriptPubKey.isSentToAddress()) else if (scriptPubKey.isSentToAddress())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey)); input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
}
else else
{
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey); throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
}
log.trace("check if it can be correctly spent for input 1"); log.trace("check if it can be correctly spent for input 1");
input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false); input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false);
@ -862,7 +905,8 @@ public class WalletFacade
// add input // add input
Transaction offerersFirstTxConnOut = wallet.getTransaction(offerersFirstTx.getInput(0).getOutpoint().getHash()); // pass that around! Transaction offerersFirstTxConnOut = wallet.getTransaction(offerersFirstTx.getInput(0).getOutpoint().getHash()); // pass that around!
TransactionOutPoint offerersFirstTxOutPoint = new TransactionOutPoint(params, offererTxOutIndex, offerersFirstTxConnOut); TransactionOutPoint offerersFirstTxOutPoint = new TransactionOutPoint(params, offererTxOutIndex, offerersFirstTxConnOut);
//TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, offerersFirstTx.getInput(0).getScriptBytes(), offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes array //TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, offerersFirstTx.getInput(0).getScriptBytes(), offerersFirstTxOutPoint); // pass that around! getScriptBytes =
// empty bytes array
TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, new byte[]{}, offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes array TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, new byte[]{}, offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes array
offerersFirstTxInput.setParent(tx); offerersFirstTxInput.setParent(tx);
tx.addInput(offerersFirstTxInput); tx.addInput(offerersFirstTxInput);
@ -884,9 +928,13 @@ public class WalletFacade
// add outputs from takers tx, they are already correct // add outputs from takers tx, they are already correct
tx.addOutput(takersSignedTx.getOutput(0)); tx.addOutput(takersSignedTx.getOutput(0));
if (takersSignedTx.getOutputs().size() > 1) if (takersSignedTx.getOutputs().size() > 1)
{
tx.addOutput(takersSignedTx.getOutput(1)); tx.addOutput(takersSignedTx.getOutput(1));
}
if (takersSignedTx.getOutputs().size() == 3) if (takersSignedTx.getOutputs().size() == 3)
{
tx.addOutput(takersSignedTx.getOutput(2)); tx.addOutput(takersSignedTx.getOutput(2));
}
printInputs("tx", tx); printInputs("tx", tx);
log.trace("tx = " + tx); log.trace("tx = " + tx);
@ -895,7 +943,9 @@ public class WalletFacade
// sign the input // sign the input
TransactionInput input = tx.getInput(0); TransactionInput input = tx.getInput(0);
if (input == null || input.getConnectedOutput() == null) if (input == null || input.getConnectedOutput() == null)
{
log.error("input or input.getConnectedOutput() is null: " + input); log.error("input or input.getConnectedOutput() is null: " + input);
}
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey(); Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet); ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
@ -903,11 +953,17 @@ public class WalletFacade
ECKey.ECDSASignature ecSig = sigKey.sign(hash); ECKey.ECDSASignature ecSig = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false); TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey()) if (scriptPubKey.isSentToRawPubKey())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig)); input.setScriptSig(ScriptBuilder.createInputScript(txSig));
}
else if (scriptPubKey.isSentToAddress()) else if (scriptPubKey.isSentToAddress())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey)); input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
}
else else
{
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey); throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
}
input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false); input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false);
log.trace("check if it can be correctly spent for input 0 OK"); log.trace("check if it can be correctly spent for input 0 OK");
@ -1089,11 +1145,7 @@ public class WalletFacade
} }
private Transaction createPayoutTx(String depositTxAsHex, private Transaction createPayoutTx(String depositTxAsHex, BigInteger offererPaybackAmount, BigInteger takerPaybackAmount, String offererAddress, String takerAddress) throws AddressFormatException
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererAddress,
String takerAddress) throws AddressFormatException
{ {
log.trace("createPayoutTx"); log.trace("createPayoutTx");
log.trace("inputs: "); log.trace("inputs: ");
@ -1116,11 +1168,17 @@ public class WalletFacade
private void printInputs(String tracePrefix, Transaction tx) private void printInputs(String tracePrefix, Transaction tx)
{ {
for (TransactionInput input : tx.getInputs()) for (TransactionInput input : tx.getInputs())
{
if (input.getConnectedOutput() != null) if (input.getConnectedOutput() != null)
{
log.trace(tracePrefix + " input value : " + BtcFormatter.formatSatoshis(input.getConnectedOutput().getValue())); log.trace(tracePrefix + " input value : " + BtcFormatter.formatSatoshis(input.getConnectedOutput().getValue()));
}
else else
{
log.trace(tracePrefix + ": " + "Transaction already has inputs but we don't have the connected outputs, so we don't know the value."); log.trace(tracePrefix + ": " + "Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
} }
}
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -1153,14 +1211,18 @@ public class WalletFacade
private void onProgressInUserThread(double percent, int blocksSoFar, final Date date) private void onProgressInUserThread(double percent, int blocksSoFar, final Date date)
{ {
for (DownloadListener downloadListener : downloadListeners) for (DownloadListener downloadListener : downloadListeners)
{
downloadListener.progress(percent); downloadListener.progress(percent);
} }
}
private void onDoneDownloadInUserThread() private void onDoneDownloadInUserThread()
{ {
for (DownloadListener downloadListener : downloadListeners) for (DownloadListener downloadListener : downloadListeners)
{
downloadListener.doneDownload(); downloadListener.doneDownload();
} }
} }
}
} }

View file

@ -48,7 +48,9 @@ public class GuiceFXMLLoader extends FXMLLoader
private void setupControllerFactory() private void setupControllerFactory()
{ {
if (GuiceFXMLLoader.injector != null) if (GuiceFXMLLoader.injector != null)
{
setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector)); setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector));
} }
}
} }

View file

@ -149,7 +149,9 @@ public class MainController implements Initializable, NavigationController
private ChildController loadView(NavigationItem navigationItem) private ChildController loadView(NavigationItem navigationItem)
{ {
if (childController != null) if (childController != null)
{
childController.cleanup(); childController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle()); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try try
@ -205,7 +207,9 @@ public class MainController implements Initializable, NavigationController
NavigationItem selectedNavigationItem = (NavigationItem) storage.read(this, "selectedNavigationItem"); NavigationItem selectedNavigationItem = (NavigationItem) storage.read(this, "selectedNavigationItem");
if (selectedNavigationItem == null) if (selectedNavigationItem == null)
{
selectedNavigationItem = NavigationItem.HOME; selectedNavigationItem = NavigationItem.HOME;
}
navigateToView(selectedNavigationItem); navigateToView(selectedNavigationItem);
} }
@ -268,7 +272,9 @@ public class MainController implements Initializable, NavigationController
childController = loadView(navigationItem); childController = loadView(navigationItem);
if (childController instanceof MarketController) if (childController instanceof MarketController)
{
((MarketController) childController).setDirection(navigationItem == NavigationItem.BUY ? Direction.BUY : Direction.SELL); ((MarketController) childController).setDirection(navigationItem == NavigationItem.BUY ? Direction.BUY : Direction.SELL);
}
storage.write(this, "selectedNavigationItem", navigationItem); storage.write(this, "selectedNavigationItem", navigationItem);

View file

@ -104,7 +104,9 @@ public class ArbitratorOverviewController implements Initializable, ChildControl
public ChildController navigateToView(NavigationItem navigationItem) public ChildController navigateToView(NavigationItem navigationItem)
{ {
if (arbitratorProfileController != null) if (arbitratorProfileController != null)
{
arbitratorProfileController.cleanup(); arbitratorProfileController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle()); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try try

View file

@ -28,8 +28,8 @@ public class ArbitratorProfileController implements Initializable, ChildControll
@FXML @FXML
private Label nameLabel; private Label nameLabel;
@FXML @FXML
private TextField nameTextField, languagesTextField, reputationTextField, maxTradeVolumeTextField, passiveServiceFeeTextField, private TextField nameTextField, languagesTextField, reputationTextField, maxTradeVolumeTextField, passiveServiceFeeTextField, arbitrationFeeTextField, methodsTextField,
arbitrationFeeTextField, methodsTextField, idVerificationsTextField, webPageTextField; idVerificationsTextField, webPageTextField;
@FXML @FXML
private TextArea descriptionTextArea; private TextArea descriptionTextArea;

View file

@ -79,8 +79,8 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
@FXML @FXML
private ComboBox<Arbitrator.ID_VERIFICATION> idVerificationsComboBox; private ComboBox<Arbitrator.ID_VERIFICATION> idVerificationsComboBox;
@FXML @FXML
private TextField nameTextField, idTypeTextField, languagesTextField, maxTradeVolumeTextField, passiveServiceFeeTextField, minPassiveServiceFeeTextField, private TextField nameTextField, idTypeTextField, languagesTextField, maxTradeVolumeTextField, passiveServiceFeeTextField, minPassiveServiceFeeTextField, arbitrationFeeTextField,
arbitrationFeeTextField, minArbitrationFeeTextField, methodsTextField, idVerificationsTextField, webPageTextField, collateralAddressTextField, balanceTextField; minArbitrationFeeTextField, methodsTextField, idVerificationsTextField, webPageTextField, collateralAddressTextField, balanceTextField;
@FXML @FXML
private TextArea descriptionTextArea; private TextArea descriptionTextArea;
@FXML @FXML
@ -467,7 +467,11 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
try try
{ {
BitSquareValidator.textFieldsNotEmptyWithReset(nameTextField, idTypeTextField, languagesTextField, methodsTextField, idVerificationsTextField); BitSquareValidator.textFieldsNotEmptyWithReset(nameTextField, idTypeTextField, languagesTextField, methodsTextField, idVerificationsTextField);
BitSquareValidator.textFieldsHasDoubleValueWithReset(maxTradeVolumeTextField, passiveServiceFeeTextField, minPassiveServiceFeeTextField, arbitrationFeeTextField, minArbitrationFeeTextField); BitSquareValidator.textFieldsHasDoubleValueWithReset(maxTradeVolumeTextField,
passiveServiceFeeTextField,
minPassiveServiceFeeTextField,
arbitrationFeeTextField,
minArbitrationFeeTextField);
String pubKeyAsHex = walletFacade.getArbitratorDepositAddressInfo().getPubKeyAsHexString(); String pubKeyAsHex = walletFacade.getArbitratorDepositAddressInfo().getPubKeyAsHexString();
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey()); String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey());

View file

@ -42,7 +42,9 @@ public class LazyLoadingTabPane extends TabPane
public void initialize(NavigationController navigationController, Storage storage, String... tabContentFXMLUrls) public void initialize(NavigationController navigationController, Storage storage, String... tabContentFXMLUrls)
{ {
if (tabContentFXMLUrls.length == 0) if (tabContentFXMLUrls.length == 0)
{
throw new IllegalArgumentException("No tabContentFXMLUrls defined"); throw new IllegalArgumentException("No tabContentFXMLUrls defined");
}
this.tabContentFXMLUrls = tabContentFXMLUrls; this.tabContentFXMLUrls = tabContentFXMLUrls;
this.navigationController = navigationController; this.navigationController = navigationController;
@ -59,8 +61,10 @@ public class LazyLoadingTabPane extends TabPane
Object indexObject = storage.read(storageId); Object indexObject = storage.read(storageId);
log.trace("saved index" + indexObject); log.trace("saved index" + indexObject);
if (indexObject != null) if (indexObject != null)
{
selectionModel.select((int) indexObject); selectionModel.select((int) indexObject);
} }
}
else else
{ {
selectionModel.select(selectedTabIndex); selectionModel.select(selectedTabIndex);
@ -72,8 +76,10 @@ public class LazyLoadingTabPane extends TabPane
public void cleanup() public void cleanup()
{ {
if (childController != null) if (childController != null)
{
childController.cleanup(); childController.cleanup();
} }
}
public ChildController navigateToView(String fxmlView) public ChildController navigateToView(String fxmlView)
@ -97,7 +103,9 @@ public class LazyLoadingTabPane extends TabPane
if (index < tabContentFXMLUrls.length && index >= 0) if (index < tabContentFXMLUrls.length && index >= 0)
{ {
if (childController != null) if (childController != null)
{
((Hibernate) childController).sleep(); ((Hibernate) childController).sleep();
}
Node view = null; Node view = null;
if (index < views.size()) if (index < views.size())

View file

@ -91,8 +91,7 @@ public class ConfidenceProgressIndicator extends Control
* Pseudoclass indicating this is a determinate (i.e., progress can be * Pseudoclass indicating this is a determinate (i.e., progress can be
* determined) progress indicator. * determined) progress indicator.
*/ */
private static final PseudoClass PSEUDO_CLASS_DETERMINATE = private static final PseudoClass PSEUDO_CLASS_DETERMINATE = PseudoClass.getPseudoClass("determinate");
PseudoClass.getPseudoClass("determinate");
/*************************************************************************** /***************************************************************************
* * * *
* Properties * * Properties *
@ -102,8 +101,7 @@ public class ConfidenceProgressIndicator extends Control
* Pseudoclass indicating this is an indeterminate (i.e., progress cannot * Pseudoclass indicating this is an indeterminate (i.e., progress cannot
* be determined) progress indicator. * be determined) progress indicator.
*/ */
private static final PseudoClass PSEUDO_CLASS_INDETERMINATE = private static final PseudoClass PSEUDO_CLASS_INDETERMINATE = PseudoClass.getPseudoClass("indeterminate");
PseudoClass.getPseudoClass("indeterminate");
/** /**
* A flag indicating whether it is possible to determine the progress * A flag indicating whether it is possible to determine the progress
* of the ProgressIndicator. Typically indeterminate progress bars are * of the ProgressIndicator. Typically indeterminate progress bars are

View file

@ -88,14 +88,16 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
* The number of segments in the spinner. * The number of segments in the spinner.
*/ */
private final IntegerProperty indeterminateSegmentCount = private final IntegerProperty indeterminateSegmentCount = new StyleableIntegerProperty(8)
new StyleableIntegerProperty(8)
{ {
@Override @Override
protected void invalidated() protected void invalidated()
{ {
if (spinner != null) spinner.rebuild(); if (spinner != null)
{
spinner.rebuild();
}
} }
@ -128,7 +130,10 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
@Override @Override
protected void invalidated() protected void invalidated()
{ {
if (spinner != null) spinner.setSpinEnabled(get()); if (spinner != null)
{
spinner.setSpinEnabled(get());
}
} }
@ -158,24 +163,27 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
* The colour of the progress segment. * The colour of the progress segment.
*/ */
private final ObjectProperty<Paint> progressColor = private final ObjectProperty<Paint> progressColor = new StyleableObjectProperty<Paint>(null)
new StyleableObjectProperty<Paint>(null)
{ {
@Override @Override
public void set(Paint newProgressColor) public void set(Paint newProgressColor)
{ {
final Paint color = (newProgressColor instanceof Color) final Paint color = (newProgressColor instanceof Color) ? newProgressColor : null;
? newProgressColor
: null;
super.set(color); super.set(color);
} }
@Override @Override
protected void invalidated() protected void invalidated()
{ {
if (spinner != null) spinner.setFillOverride(get()); if (spinner != null)
if (determinateIndicator != null) determinateIndicator.setFillOverride(get()); {
spinner.setFillOverride(get());
}
if (determinateIndicator != null)
{
determinateIndicator.setFillOverride(get());
}
} }
@ -338,8 +346,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
} }
@Override @Override
protected void layoutChildren(final double x, final double y, protected void layoutChildren(final double x, final double y, final double w, final double h)
final double w, final double h)
{ {
if (spinner != null && getSkinnable().isIndeterminate()) if (spinner != null && getSkinnable().isIndeterminate())
{ {
@ -509,9 +516,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
final double iRight = snapSize(indicatorInsets.getRight()); final double iRight = snapSize(indicatorInsets.getRight());
final double iTop = snapSize(indicatorInsets.getTop()); final double iTop = snapSize(indicatorInsets.getTop());
final double iBottom = snapSize(indicatorInsets.getBottom()); final double iBottom = snapSize(indicatorInsets.getBottom());
final double progressRadius = snapSize(Math.min( final double progressRadius = snapSize(Math.min(Math.min(radius - iLeft, radius - iRight), Math.min(radius - iTop, radius - iBottom)));
Math.min(radius - iLeft, radius - iRight),
Math.min(radius - iTop, radius - iBottom)));
indicatorCircle.setRadius(radius); indicatorCircle.setRadius(radius);
indicator.setLayoutX(centerX); indicator.setLayoutX(centerX);
@ -528,9 +533,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
final double pRight = snapSize(progressInsets.getRight()); final double pRight = snapSize(progressInsets.getRight());
final double pTop = snapSize(progressInsets.getTop()); final double pTop = snapSize(progressInsets.getTop());
final double pBottom = snapSize(progressInsets.getBottom()); final double pBottom = snapSize(progressInsets.getBottom());
final double indicatorRadius = snapSize(Math.min( final double indicatorRadius = snapSize(Math.min(Math.min(progressRadius - pLeft, progressRadius - pRight), Math.min(progressRadius - pTop, progressRadius - pBottom)));
Math.min(progressRadius - pLeft, progressRadius - pRight),
Math.min(progressRadius - pTop, progressRadius - pBottom)));
// find size of spare box that fits inside indicator radius // find size of spare box that fits inside indicator radius
double squareBoxHalfWidth = Math.ceil(Math.sqrt((indicatorRadius * indicatorRadius) / 2)); double squareBoxHalfWidth = Math.ceil(Math.sqrt((indicatorRadius * indicatorRadius) / 2));
@ -680,9 +683,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
} }
for (int i = 100; i <= 3900; i += 100) for (int i = 100; i <= 3900; i += 100)
{ {
keyFrames.add( keyFrames.add(new KeyFrame(Duration.millis(i), event -> shiftColors()));
new KeyFrame(
Duration.millis(i), event -> shiftColors()));
} }
indeterminateTimeline.getKeyFrames().setAll(keyFrames); indeterminateTimeline.getKeyFrames().setAll(keyFrames);
} }
@ -750,7 +751,10 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
private void shiftColors() private void shiftColors()
{ {
if (opacities.size() <= 0) return; if (opacities.size() <= 0)
{
return;
}
final int segments = skin.indeterminateSegmentCount.get(); final int segments = skin.indeterminateSegmentCount.get();
Collections.rotate(opacities, -1); Collections.rotate(opacities, -1);
for (int i = 0; i < segments; i++) for (int i = 0; i < segments; i++)
@ -834,10 +838,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
Region region = (Region) child; Region region = (Region) child;
if (region.getShape() != null) if (region.getShape() != null)
{ {
region.resize( region.resize(region.getShape().getLayoutBounds().getMaxX(), region.getShape().getLayoutBounds().getMaxY());
region.getShape().getLayoutBounds().getMaxX(),
region.getShape().getLayoutBounds().getMaxY()
);
region.getTransforms().setAll(new Scale(scale, scale, 0, 0)); region.getTransforms().setAll(new Scale(scale, scale, 0, 0));
} }
else else
@ -857,17 +858,16 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
{ {
public static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; public static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
private static final CssMetaData<ConfidenceProgressIndicator, Paint> PROGRESS_COLOR = private static final CssMetaData<ConfidenceProgressIndicator, Paint> PROGRESS_COLOR = new CssMetaData<ConfidenceProgressIndicator, Paint>("-fx-progress-color",
new CssMetaData<ConfidenceProgressIndicator, Paint>("-fx-progress-color", PaintConverter.getInstance(),
PaintConverter.getInstance(), null) null)
{ {
@Override @Override
public boolean isSettable(ConfidenceProgressIndicator n) public boolean isSettable(ConfidenceProgressIndicator n)
{ {
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin(); final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return skin.progressColor == null || return skin.progressColor == null || !skin.progressColor.isBound();
!skin.progressColor.isBound();
} }
@ -880,9 +880,9 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
}; };
private static final CssMetaData<ConfidenceProgressIndicator, Number> INDETERMINATE_SEGMENT_COUNT = private static final CssMetaData<ConfidenceProgressIndicator, Number> INDETERMINATE_SEGMENT_COUNT = new CssMetaData<ConfidenceProgressIndicator, Number>("-fx-indeterminate-segment-count",
new CssMetaData<ConfidenceProgressIndicator, Number>("-fx-indeterminate-segment-count", SizeConverter.getInstance(),
SizeConverter.getInstance(), 8) 8)
{ {
@Override @Override
@ -895,8 +895,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
public boolean isSettable(ConfidenceProgressIndicator n) public boolean isSettable(ConfidenceProgressIndicator n)
{ {
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin(); final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return skin.indeterminateSegmentCount == null || return skin.indeterminateSegmentCount == null || !skin.indeterminateSegmentCount.isBound();
!skin.indeterminateSegmentCount.isBound();
} }
@ -908,9 +907,9 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
} }
}; };
private static final CssMetaData<ConfidenceProgressIndicator, Boolean> SPIN_ENABLED = private static final CssMetaData<ConfidenceProgressIndicator, Boolean> SPIN_ENABLED = new CssMetaData<ConfidenceProgressIndicator, Boolean>("-fx-spin-enabled",
new CssMetaData<ConfidenceProgressIndicator, Boolean>("-fx-spin-enabled", BooleanConverter.getInstance(),
BooleanConverter.getInstance(), Boolean.FALSE) Boolean.FALSE)
{ {
@Override @Override

View file

@ -37,8 +37,10 @@ public class ProcessStepBar<T> extends Control
{ {
this.processStepItems = processStepItems; this.processStepItems = processStepItems;
if (getSkin() != null) if (getSkin() != null)
{
((ProcessStepBarSkin) getSkin()).dataChanged(); ((ProcessStepBarSkin) getSkin()).dataChanged();
} }
}
public void next() public void next()
{ {

View file

@ -52,7 +52,9 @@ class ProcessStepBarSkin<T> extends BehaviorSkinBase<ProcessStepBar<T>, Behavior
getChildren().add(labelWithBorder); getChildren().add(labelWithBorder);
labelWithBorders.add(labelWithBorder); labelWithBorders.add(labelWithBorder);
if (i == 0) if (i == 0)
{
currentLabelWithBorder = prevLabelWithBorder = labelWithBorder; currentLabelWithBorder = prevLabelWithBorder = labelWithBorder;
}
i++; i++;
} }
@ -88,7 +90,9 @@ class ProcessStepBarSkin<T> extends BehaviorSkinBase<ProcessStepBar<T>, Behavior
double newHeight = snapSize(node.prefHeight(-1) + 10); double newHeight = snapSize(node.prefHeight(-1) + 10);
if (i > 0) if (i > 0)
{
x = snapPosition(x - ((LabelWithBorder) node).getArrowWidth()); x = snapPosition(x - ((LabelWithBorder) node).getArrowWidth());
}
x = snapPosition(x); x = snapPosition(x);
y = snapPosition(y); y = snapPosition(y);
@ -124,15 +128,13 @@ class ProcessStepBarSkin<T> extends BehaviorSkinBase<ProcessStepBar<T>, Behavior
this.setShape(createButtonShape()); this.setShape(createButtonShape());
BorderStroke borderStroke = new BorderStroke(Color.LIGHTGRAY, BorderStrokeStyle.SOLID, null, BorderStroke borderStroke = new BorderStroke(Color.LIGHTGRAY, BorderStrokeStyle.SOLID, null, new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
this.setBorder(new Border(borderStroke)); this.setBorder(new Border(borderStroke));
} }
public void select() public void select()
{ {
BorderStroke borderStroke = new BorderStroke(processStepItem.getColor(), BorderStrokeStyle.SOLID, null, BorderStroke borderStroke = new BorderStroke(processStepItem.getColor(), BorderStrokeStyle.SOLID, null, new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
this.setBorder(new Border(borderStroke)); this.setBorder(new Border(borderStroke));
setTextFill(processStepItem.getColor()); setTextFill(processStepItem.getColor());
} }

View file

@ -160,7 +160,10 @@ public class WithdrawalController implements Initializable, ChildController, Hib
public void onSuccess(@javax.annotation.Nullable Transaction transaction) public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{ {
BitSquareValidator.resetTextFields(withdrawFromTextField, withdrawToTextField, amountTextField, changeAddressTextField); BitSquareValidator.resetTextFields(withdrawFromTextField, withdrawToTextField, amountTextField, changeAddressTextField);
if (transaction != null) log.info("onWithdraw onSuccess txid:" + transaction.getHashAsString()); if (transaction != null)
{
log.info("onWithdraw onSuccess txid:" + transaction.getHashAsString());
}
} }
@Override @Override

View file

@ -126,9 +126,13 @@ public class WithdrawalListItem
return "Registration fee"; return "Registration fee";
case TRADE: case TRADE:
if (addressEntry.getTradeId() != null) if (addressEntry.getTradeId() != null)
{
return "Trade ID: " + addressEntry.getTradeId(); return "Trade ID: " + addressEntry.getTradeId();
}
else else
{
return "Trade (not used yet)"; return "Trade (not used yet)";
}
case ARBITRATOR_DEPOSIT: case ARBITRATOR_DEPOSIT:
return "Arbitration deposit"; return "Arbitration deposit";
} }

View file

@ -50,7 +50,9 @@ public class HomeController implements Initializable, ChildController, Navigatio
public ChildController navigateToView(NavigationItem navigationItem) public ChildController navigateToView(NavigationItem navigationItem)
{ {
if (arbitratorRegistrationController != null) if (arbitratorRegistrationController != null)
{
arbitratorRegistrationController.cleanup(); arbitratorRegistrationController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle()); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try try

View file

@ -60,7 +60,9 @@ public class MarketController implements Initializable, NavigationController, Ch
childController.setNavigationController(this); childController.setNavigationController(this);
if (childController instanceof OrderBookController) if (childController instanceof OrderBookController)
{
orderBookController = (OrderBookController) childController; orderBookController = (OrderBookController) childController;
}
String tabLabel; String tabLabel;
switch (navigationItem) switch (navigationItem)
@ -125,8 +127,10 @@ public class MarketController implements Initializable, NavigationController, Ch
{ {
tabPane.getSelectionModel().select(0); tabPane.getSelectionModel().select(0);
if (orderBookController != null) if (orderBookController != null)
{
orderBookController.setDirection(direction); orderBookController.setDirection(direction);
} }
}
} }

View file

@ -63,8 +63,8 @@ public class CreateOfferController implements Initializable, ChildController, Hi
@FXML @FXML
private Button placeOfferButton, closeButton; private Button placeOfferButton, closeButton;
@FXML @FXML
private TextField collateralTextField, minAmountTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, private TextField collateralTextField, minAmountTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField,
acceptedCountriesTextField, acceptedLanguagesTextField, feeLabel, txTextField; acceptedLanguagesTextField, feeLabel, txTextField;
@FXML @FXML
private ConfidenceProgressIndicator progressIndicator; private ConfidenceProgressIndicator progressIndicator;

View file

@ -220,7 +220,8 @@ public class OrderBookController implements Initializable, ChildController
} }
else else
{ {
Action response = Popups.openErrorPopup("Registration fee not confirmed yet", "The registration fee transaction has not been confirmed yet in the blockchain. Please wait until it has at least 1 confirmation."); Action response = Popups.openErrorPopup("Registration fee not confirmed yet",
"The registration fee transaction has not been confirmed yet in the blockchain. Please wait until it has at least 1 confirmation.");
if (response == Dialog.Actions.OK) if (response == Dialog.Actions.OK)
{ {
MainController.GET_INSTANCE().navigateToView(NavigationItem.FUNDS); MainController.GET_INSTANCE().navigateToView(NavigationItem.FUNDS);
@ -229,7 +230,8 @@ public class OrderBookController implements Initializable, ChildController
} }
else else
{ {
Action response = Popups.openErrorPopup("Missing registration fee", "You have not funded the full registration fee of " + BtcFormatter.formatSatoshis(FeePolicy.ACCOUNT_REGISTRATION_FEE) + " BTC."); Action response = Popups.openErrorPopup("Missing registration fee",
"You have not funded the full registration fee of " + BtcFormatter.formatSatoshis(FeePolicy.ACCOUNT_REGISTRATION_FEE) + " BTC.");
if (response == Dialog.Actions.OK) if (response == Dialog.Actions.OK)
{ {
MainController.GET_INSTANCE().navigateToView(NavigationItem.FUNDS); MainController.GET_INSTANCE().navigateToView(NavigationItem.FUNDS);
@ -249,10 +251,17 @@ public class OrderBookController implements Initializable, ChildController
if (selectedIndex >= 0) if (selectedIndex >= 0)
{ {
Dialogs.CommandLink settingsCommandLink = new Dialogs.CommandLink("Open settings", "You need to configure your settings before you can actively trade."); Dialogs.CommandLink settingsCommandLink = new Dialogs.CommandLink("Open settings", "You need to configure your settings before you can actively trade.");
Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds", "You need to pay the registration fee before you can actively trade. That is needed as prevention against fraud."); Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds",
Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration", "When settings are configured and the fee deposit is done your registration transaction will be published to the Bitcoin \nnetwork."); "You need to pay the registration fee before you can actively trade. That is needed as prevention against fraud.");
Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration",
"When settings are configured and the fee deposit is done your registration transaction will be published to "
+ "the Bitcoin \nnetwork.");
List<Dialogs.CommandLink> commandLinks = Arrays.asList(settingsCommandLink, depositFeeCommandLink, sendRegistrationCommandLink); List<Dialogs.CommandLink> commandLinks = Arrays.asList(settingsCommandLink, depositFeeCommandLink, sendRegistrationCommandLink);
Action registrationMissingAction = Popups.openRegistrationMissingPopup("Not registered yet", "Please follow these steps:", "You need to register before you can place an offer.", commandLinks, selectedIndex); Action registrationMissingAction = Popups.openRegistrationMissingPopup("Not registered yet",
"Please follow these steps:",
"You need to register before you can place an offer.",
commandLinks,
selectedIndex);
if (registrationMissingAction == settingsCommandLink) if (registrationMissingAction == settingsCommandLink)
{ {
MainController.GET_INSTANCE().navigateToView(NavigationItem.SETTINGS); MainController.GET_INSTANCE().navigateToView(NavigationItem.SETTINGS);
@ -276,7 +285,10 @@ public class OrderBookController implements Initializable, ChildController
public void onSuccess(@javax.annotation.Nullable Transaction transaction) public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{ {
log.debug("payRegistrationFee onSuccess"); log.debug("payRegistrationFee onSuccess");
if (transaction != null) log.info("payRegistrationFee onSuccess tx id:" + transaction.getHashAsString()); if (transaction != null)
{
log.info("payRegistrationFee onSuccess tx id:" + transaction.getHashAsString());
}
} }
@Override @Override
@ -289,8 +301,13 @@ public class OrderBookController implements Initializable, ChildController
{ {
walletFacade.payRegistrationFee(user.getStringifiedBankAccounts(), callback); walletFacade.payRegistrationFee(user.getStringifiedBankAccounts(), callback);
if (walletFacade.getRegistrationAddressInfo() != null) if (walletFacade.getRegistrationAddressInfo() != null)
{
user.setAccountID(walletFacade.getRegistrationAddressInfo().toString()); user.setAccountID(walletFacade.getRegistrationAddressInfo().toString());
if (messageFacade != null && messageFacade.getPubKey() != null) user.setMessagePubKeyAsHex(DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey())); }
if (messageFacade != null && messageFacade.getPubKey() != null)
{
user.setMessagePubKeyAsHex(DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey()));
}
storage.write(user.getClass().getName(), user); storage.write(user.getClass().getName(), user);
} catch (InsufficientMoneyException e1) } catch (InsufficientMoneyException e1)
@ -308,8 +325,10 @@ public class OrderBookController implements Initializable, ChildController
{ {
ChildController nextController = navigationController.navigateToView(NavigationItem.CREATE_OFFER); ChildController nextController = navigationController.navigateToView(NavigationItem.CREATE_OFFER);
if (nextController != null) if (nextController != null)
{
((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter); ((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter);
} }
}
else else
{ {
Action response = Popups.openErrorPopup("No funds for a trade", "You have to add some funds before you create a new offer."); Action response = Popups.openErrorPopup("No funds for a trade", "You have to add some funds before you create a new offer.");
@ -333,13 +352,19 @@ public class OrderBookController implements Initializable, ChildController
BigInteger requestedAmount; BigInteger requestedAmount;
if (!"".equals(amount.getText())) if (!"".equals(amount.getText()))
{
requestedAmount = BtcFormatter.stringValueToSatoshis(amount.getText()); requestedAmount = BtcFormatter.stringValueToSatoshis(amount.getText());
}
else else
{
requestedAmount = offer.getAmount(); requestedAmount = offer.getAmount();
}
if (takerOfferController != null) if (takerOfferController != null)
{
takerOfferController.initWithData(offer, requestedAmount); takerOfferController.initWithData(offer, requestedAmount);
} }
}
else else
{ {
showRegistrationDialog(); showRegistrationDialog();
@ -359,16 +384,22 @@ public class OrderBookController implements Initializable, ChildController
orderBookTable.sort(); orderBookTable.sort();
if (orderBookTable.getItems() != null) if (orderBookTable.getItems() != null)
{
createOfferButton.setDefaultButton(orderBookTable.getItems().isEmpty()); createOfferButton.setDefaultButton(orderBookTable.getItems().isEmpty());
} }
}
private void setupPolling() private void setupPolling()
{ {
pollingTimer = Utilities.setInterval(1000, (animationTimer) -> { pollingTimer = Utilities.setInterval(1000, (animationTimer) -> {
if (user.getCurrentBankAccount() != null) if (user.getCurrentBankAccount() != null)
{
messageFacade.getDirtyFlag(user.getCurrentBankAccount().getCurrency()); messageFacade.getDirtyFlag(user.getCurrentBankAccount().getCurrency());
}
else else
{
messageFacade.getDirtyFlag(CurrencyUtil.getDefaultCurrency()); messageFacade.getDirtyFlag(CurrencyUtil.getDefaultCurrency());
}
return null; return null;
}); });

View file

@ -17,8 +17,8 @@ import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.Trading; import io.bitsquare.trade.Trading;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocol; import io.bitsquare.trade.protocol.taker.ProtocolForTakerAsSeller;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocolListener; import io.bitsquare.trade.protocol.taker.ProtocolForTakerAsSellerListener;
import java.math.BigInteger; import java.math.BigInteger;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -53,9 +53,9 @@ public class TakerOfferController implements Initializable, ChildController
@FXML @FXML
private ValidatedTextField amountTextField; private ValidatedTextField amountTextField;
@FXML @FXML
private TextField priceTextField, volumeTextField, collateralTextField, feeTextField, totalTextField, bankAccountTypeTextField, countryTextField, private TextField priceTextField, volumeTextField, collateralTextField, feeTextField, totalTextField, bankAccountTypeTextField, countryTextField, arbitratorsTextField,
arbitratorsTextField, supportedLanguagesTextField, supportedCountriesTextField, depositTxIdTextField, summaryPaidTextField, summaryReceivedTextField, summaryFeesTextField, supportedLanguagesTextField, supportedCountriesTextField, depositTxIdTextField, summaryPaidTextField, summaryReceivedTextField, summaryFeesTextField, summaryCollateralTextField,
summaryCollateralTextField, summaryDepositTxIdTextField, summaryPayoutTxIdTextField; summaryDepositTxIdTextField, summaryPayoutTxIdTextField;
@FXML @FXML
private Label infoLabel, headLineLabel; private Label infoLabel, headLineLabel;
@FXML @FXML
@ -84,8 +84,10 @@ public class TakerOfferController implements Initializable, ChildController
this.requestedAmount = requestedAmount.compareTo(BigInteger.ZERO) == 0 ? offer.getAmount() : requestedAmount; this.requestedAmount = requestedAmount.compareTo(BigInteger.ZERO) == 0 ? offer.getAmount() : requestedAmount;
if (amountTextField != null) if (amountTextField != null)
{
applyData(); applyData();
} }
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: Initializable // Interface implementation: Initializable
@ -172,7 +174,7 @@ public class TakerOfferController implements Initializable, ChildController
{ {
takeOfferButton.setDisable(true); takeOfferButton.setDisable(true);
amountTextField.setEditable(false); amountTextField.setEditable(false);
trading.takeOffer(amount, offer, new TakerAsSellerProtocolListener() trading.takeOffer(amount, offer, new ProtocolForTakerAsSellerListener()
{ {
@Override @Override
public void onDepositTxPublished(String depositTxId) public void onDepositTxPublished(String depositTxId)
@ -190,8 +192,7 @@ public class TakerOfferController implements Initializable, ChildController
{ {
setTradeId(tradeId); setTradeId(tradeId);
headLineLabel.setText("Bank transfer inited"); headLineLabel.setText("Bank transfer inited");
infoLabel.setText("Check your bank account and continue \n" + infoLabel.setText("Check your bank account and continue \n" + "when you have received the money.");
"when you have received the money.");
receivedFiatButton.setDisable(false); receivedFiatButton.setDisable(false);
} }
@ -208,20 +209,20 @@ public class TakerOfferController implements Initializable, ChildController
} }
@Override @Override
public void onFault(Throwable throwable, TakerAsSellerProtocol.State state) public void onFault(Throwable throwable, ProtocolForTakerAsSeller.State state)
{ {
log.error("Error while executing trade process at state: " + state + " / " + throwable); log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable); Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable);
} }
@Override @Override
public void onWaitingForPeerResponse(TakerAsSellerProtocol.State state) public void onWaitingForPeerResponse(ProtocolForTakerAsSeller.State state)
{ {
log.debug("Waiting for peers response at state " + state); log.debug("Waiting for peers response at state " + state);
} }
@Override @Override
public void onCompleted(TakerAsSellerProtocol.State state) public void onCompleted(ProtocolForTakerAsSeller.State state)
{ {
log.debug("Trade protocol completed at state " + state); log.debug("Trade protocol completed at state " + state);
} }
@ -230,10 +231,10 @@ public class TakerOfferController implements Initializable, ChildController
public void onTakeOfferRequestRejected(Trade trade) public void onTakeOfferRequestRejected(Trade trade)
{ {
log.error("Take offer request rejected"); log.error("Take offer request rejected");
Popups.openErrorPopup("Take offer request rejected", "Your take offer request has been rejected. It might be that the offerer got another request shortly before your request arrived."); Popups.openErrorPopup("Take offer request rejected",
"Your take offer request has been rejected. It might be that the offerer got another request shortly before your request arrived.");
} }
} });
);
} }
} }

View file

@ -196,7 +196,9 @@ public class TakerTradeController implements Initializable, ChildController
try try
{ {
if (offer.getArbitrator() != null && offer.getArbitrator().getWebUrl() != null) if (offer.getArbitrator() != null && offer.getArbitrator().getWebUrl() != null)
{
Utilities.openURL(offer.getArbitrator().getWebUrl()); Utilities.openURL(offer.getArbitrator().getWebUrl());
}
} catch (Exception e1) } catch (Exception e1)
{ {
log.warn(e1.toString()); log.warn(e1.toString());
@ -230,13 +232,13 @@ public class TakerTradeController implements Initializable, ChildController
trade = trading.createTrade(offer); trade = trading.createTrade(offer);
trade.setTradeAmount(BtcFormatter.stringValueToSatoshis(amountTextField.getText())); trade.setTradeAmount(BtcFormatter.stringValueToSatoshis(amountTextField.getText()));
/* if (!blockChainFacade.verifyAccountRegistration(offer.getAccountId())) /* if (!blockChainFacade.verifyAccountRegistration(offer.getTakerAccountId()))
{ {
Popups.openErrorPopup("Offerers account ID not valid", "Offerers registration tx is not found in blockchain or does not match the requirements."); Popups.openErrorPopup("Offerers account ID not valid", "Offerers registration tx is not found in blockchain or does not match the requirements.");
return; return;
} }
if (blockChainFacade.isAccountIDBlacklisted(offer.getAccountId())) if (blockChainFacade.isAccountIDBlacklisted(offer.getTakerAccountId()))
{ {
Popups.openErrorPopup("Offerers account ID is blacklisted", "Offerers account ID is blacklisted."); Popups.openErrorPopup("Offerers account ID is blacklisted", "Offerers account ID is blacklisted.");
return; return;

View file

@ -155,7 +155,9 @@ public class PendingTradeController implements Initializable, ChildController, H
trading.getNewTradeProperty().addListener((observableValue, oldTradeId, newTradeId) -> { trading.getNewTradeProperty().addListener((observableValue, oldTradeId, newTradeId) -> {
Trade newTrade = trading.getTrade(newTradeId); Trade newTrade = trading.getTrade(newTradeId);
if (newTrade != null) if (newTrade != null)
{
tradeItems.add(new PendingTradesListItem(newTrade)); tradeItems.add(new PendingTradesListItem(newTrade));
}
}); });
initCopyIcons(); initCopyIcons();
@ -163,7 +165,9 @@ public class PendingTradeController implements Initializable, ChildController, H
// select // select
Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) -> e.getTrade().getId().equals(trading.getPendingTrade().getId())).findFirst(); Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) -> e.getTrade().getId().equals(trading.getPendingTrade().getId())).findFirst();
if (currentTradeItemOptional.isPresent()) if (currentTradeItemOptional.isPresent())
{
openTradesTable.getSelectionModel().select(currentTradeItemOptional.get()); openTradesTable.getSelectionModel().select(currentTradeItemOptional.get());
}
tradeItems.addListener((ListChangeListener<PendingTradesListItem>) change -> { tradeItems.addListener((ListChangeListener<PendingTradesListItem>) change -> {
if (openTradesTable.getSelectionModel().getSelectedItem() == null && tradeItems.size() > 0) if (openTradesTable.getSelectionModel().getSelectedItem() == null && tradeItems.size() > 0)

View file

@ -22,12 +22,7 @@ public class Popups
public static void openInformationPopup(String title, String message, String masthead) public static void openInformationPopup(String title, String message, String masthead)
{ {
Dialogs.create() Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showInformation();
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showInformation();
} }
// Confirm // Confirm
@ -41,13 +36,7 @@ public class Popups
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
actions.add(Dialog.Actions.OK); actions.add(Dialog.Actions.OK);
actions.add(Dialog.Actions.CANCEL); actions.add(Dialog.Actions.CANCEL);
return Dialogs.create() return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).actions(actions).showConfirm();
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.actions(actions)
.showConfirm();
} }
// Warning // Warning
@ -63,12 +52,7 @@ public class Popups
public static void openWarningPopup(String title, String message, String masthead) public static void openWarningPopup(String title, String message, String masthead)
{ {
Dialogs.create() Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showWarning();
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showWarning();
} }
// Error // Error
@ -84,12 +68,7 @@ public class Popups
public static Action openErrorPopup(String title, String message, String masthead) public static Action openErrorPopup(String title, String message, String masthead)
{ {
return Dialogs.create() return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showError();
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showError();
} }
// Exception // Exception
@ -105,12 +84,7 @@ public class Popups
public static Action openExceptionPopup(Throwable throwable, String title, String message, String masthead) public static Action openExceptionPopup(Throwable throwable, String title, String message, String masthead)
{ {
return Dialogs.create() return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showException(throwable);
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showException(throwable);
} }
// Support handling of uncaught exception from any thread (also non gui thread) // Support handling of uncaught exception from any thread (also non gui thread)
@ -120,26 +94,36 @@ public class Popups
// while dev // while dev
throwable.printStackTrace(); throwable.printStackTrace();
Runnable runnable = () -> Runnable runnable = () -> {
{
if (Throwables.getRootCause(throwable) instanceof BlockStoreException) if (Throwables.getRootCause(throwable) instanceof BlockStoreException)
{ {
Action response = Popups.openErrorPopup("Application already running", "This application is already running and cannot be started twice.", ""); Action response = Popups.openErrorPopup("Application already running", "This application is already running and cannot be started twice.", "");
if (response == Dialog.Actions.OK) if (response == Dialog.Actions.OK)
{
Platform.exit(); Platform.exit();
} }
}
else else
{ {
Action response = Popups.openExceptionPopup(throwable, "Exception", "", "A critical error has occurred.\nPlease copy the exception details and send a bug report to bugs@bitsquare.io."); Action response = Popups.openExceptionPopup(throwable,
"Exception",
"",
"A critical error has occurred.\nPlease copy the exception details and send a bug report to bugs@bitsquare.io.");
if (response == Dialog.Actions.OK) if (response == Dialog.Actions.OK)
{
Platform.exit(); Platform.exit();
} }
}
}; };
if (Platform.isFxApplicationThread()) if (Platform.isFxApplicationThread())
{
runnable.run(); runnable.run();
}
else else
{
Platform.runLater(runnable); Platform.runLater(runnable);
}
} }
@ -152,11 +136,6 @@ public class Popups
public static Action openRegistrationMissingPopup(String title, String message, String masthead, List<Dialogs.CommandLink> commandLinks, int selectedIndex) public static Action openRegistrationMissingPopup(String title, String message, String masthead, List<Dialogs.CommandLink> commandLinks, int selectedIndex)
{ {
return Dialogs.create() return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showCommandLinks(commandLinks.get(selectedIndex), commandLinks);
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showCommandLinks(commandLinks.get(selectedIndex), commandLinks);
} }
} }

View file

@ -162,8 +162,7 @@ public class SettingsController implements Initializable, ChildController, Navig
arbitrationMethods, arbitrationMethods,
idVerifications, idVerifications,
"http://bitsquare.io/", "http://bitsquare.io/",
"Bla bla..." "Bla bla...");
);
arbitratorList.add(arbitrator); arbitratorList.add(arbitrator);
settings.addAcceptedArbitrator(arbitrator); settings.addAcceptedArbitrator(arbitrator);
@ -207,7 +206,9 @@ public class SettingsController implements Initializable, ChildController, Navig
{ {
if (childController != null) if (childController != null)
{
childController.cleanup(); childController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle()); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try try
@ -231,7 +232,9 @@ public class SettingsController implements Initializable, ChildController, Navig
stage.setScene(scene); stage.setScene(scene);
stage.setOnHidden(windowEvent -> { stage.setOnHidden(windowEvent -> {
if (navigationItem == NavigationItem.ARBITRATOR_OVERVIEW) if (navigationItem == NavigationItem.ARBITRATOR_OVERVIEW)
{
updateArbitrators(); updateArbitrators();
}
}); });
stage.show(); stage.show();
@ -395,8 +398,7 @@ public class SettingsController implements Initializable, ChildController, Navig
} }
}; };
} }
} });
);
languagesListView.setItems(languageList); languagesListView.setItems(languageList);
languageComboBox.setItems(FXCollections.observableArrayList(LanguageUtil.getAllLanguageLocales())); languageComboBox.setItems(FXCollections.observableArrayList(LanguageUtil.getAllLanguageLocales()));
@ -482,8 +484,7 @@ public class SettingsController implements Initializable, ChildController, Navig
} }
}; };
} }
} });
);
countriesListView.setItems(countryList); countriesListView.setItems(countryList);
countryComboBox.setConverter(new StringConverter<Country>() countryComboBox.setConverter(new StringConverter<Country>()
@ -553,8 +554,7 @@ public class SettingsController implements Initializable, ChildController, Navig
} }
}; };
} }
} });
);
arbitratorsListView.setItems(arbitratorList); arbitratorsListView.setItems(arbitratorList);
} }
@ -645,8 +645,10 @@ public class SettingsController implements Initializable, ChildController, Navig
bankAccountPrimaryIDTextField.setText("dummy"); bankAccountPrimaryIDTextField.setText("dummy");
bankAccountSecondaryIDTextField.setText("dummy"); bankAccountSecondaryIDTextField.setText("dummy");
if (user.getCurrentBankAccount() == null) if (user.getCurrentBankAccount() == null)
{
onSaveBankAccount(); onSaveBankAccount();
} }
}
private void resetBankAccountInput() private void resetBankAccountInput()
{ {
@ -809,8 +811,7 @@ public class SettingsController implements Initializable, ChildController, Navig
{ {
if (verifyBankAccountData()) if (verifyBankAccountData())
{ {
BankAccount bankAccount = new BankAccount( BankAccount bankAccount = new BankAccount(bankAccountTypesComboBox.getSelectionModel().getSelectedItem(),
bankAccountTypesComboBox.getSelectionModel().getSelectedItem(),
bankAccountCurrencyComboBox.getSelectionModel().getSelectedItem(), bankAccountCurrencyComboBox.getSelectionModel().getSelectedItem(),
bankAccountCountryComboBox.getSelectionModel().getSelectedItem(), bankAccountCountryComboBox.getSelectionModel().getSelectedItem(),
bankAccountTitleTextField.getText(), bankAccountTitleTextField.getText(),
@ -844,9 +845,10 @@ public class SettingsController implements Initializable, ChildController, Navig
BitSquareValidator.textFieldBankAccountPrimaryIDIsValid(bankAccountPrimaryIDTextField, bankAccountTypeInfo); BitSquareValidator.textFieldBankAccountPrimaryIDIsValid(bankAccountPrimaryIDTextField, bankAccountTypeInfo);
BitSquareValidator.textFieldBankAccountSecondaryIDIsValid(bankAccountSecondaryIDTextField, bankAccountTypeInfo); BitSquareValidator.textFieldBankAccountSecondaryIDIsValid(bankAccountSecondaryIDTextField, bankAccountTypeInfo);
return bankAccountTypesComboBox.getSelectionModel().getSelectedItem() != null return bankAccountTypesComboBox.getSelectionModel().getSelectedItem() != null && bankAccountCountryComboBox.getSelectionModel()
&& bankAccountCountryComboBox.getSelectionModel().getSelectedItem() != null .getSelectedItem() != null && bankAccountCurrencyComboBox.getSelectionModel()
&& bankAccountCurrencyComboBox.getSelectionModel().getSelectedItem() != null; .getSelectedItem() !=
null;
} catch (BitSquareValidator.ValidationException e) } catch (BitSquareValidator.ValidationException e)
{ {
return false; return false;

View file

@ -50,10 +50,14 @@ public class BitSquareFormatter
public static String formatAmountWithMinAmount(double amount, double minAmount, boolean useBTC) public static String formatAmountWithMinAmount(double amount, double minAmount, boolean useBTC)
{ {
if (useBTC) if (useBTC)
{
return formatDouble(amount) + " BTC (" + formatDouble(minAmount) + " BTC)"; return formatDouble(amount) + " BTC (" + formatDouble(minAmount) + " BTC)";
}
else else
{
return formatDouble(amount) + " (" + formatDouble(minAmount) + ")"; return formatDouble(amount) + " (" + formatDouble(minAmount) + ")";
} }
}
public static String formatAmountWithMinAmount(double amount, double minAmount) public static String formatAmountWithMinAmount(double amount, double minAmount)
@ -95,7 +99,9 @@ public class BitSquareFormatter
{ {
String result = (direction == Direction.BUY) ? "Buy" : "Sell"; String result = (direction == Direction.BUY) ? "Buy" : "Sell";
if (allUpperCase) if (allUpperCase)
{
result = result.toUpperCase(); result = result.toUpperCase();
}
return result; return result;
} }
@ -143,8 +149,10 @@ public class BitSquareFormatter
result += country.getName(); result += country.getName();
i++; i++;
if (i < countries.size()) if (i < countries.size())
{
result += ", "; result += ", ";
} }
}
return result; return result;
} }
@ -157,8 +165,10 @@ public class BitSquareFormatter
result += locale.getDisplayLanguage(); result += locale.getDisplayLanguage();
i++; i++;
if (i < languageLocales.size()) if (i < languageLocales.size())
{
result += ", "; result += ", ";
} }
}
return result; return result;
} }
@ -172,8 +182,10 @@ public class BitSquareFormatter
result += Localisation.get(item.toString()); result += Localisation.get(item.toString());
i++; i++;
if (i < items.size()) if (i < items.size())
{
result += ", "; result += ", ";
} }
}
return result; return result;
} }
@ -187,8 +199,10 @@ public class BitSquareFormatter
result += Localisation.get(item.toString()); result += Localisation.get(item.toString());
i++; i++;
if (i < items.size()) if (i < items.size())
{
result += ", "; result += ", ";
} }
}
return result; return result;
} }

View file

@ -107,7 +107,9 @@ public class ConfidenceDisplay
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{ {
if (tx.getHashAsString().equals(transaction.getHashAsString())) if (tx.getHashAsString().equals(transaction.getHashAsString()))
{
updateBalance(newBalance); updateBalance(newBalance);
}
// log.debug("onCoinsReceived " + newBalance); // log.debug("onCoinsReceived " + newBalance);
} }
@ -115,7 +117,9 @@ public class ConfidenceDisplay
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{ {
if (tx.getHashAsString().equals(transaction.getHashAsString())) if (tx.getHashAsString().equals(transaction.getHashAsString()))
{
updateConfidence(transaction); updateConfidence(transaction);
}
// log.debug("onTransactionConfidenceChanged newTransaction " + newTransaction.getHashAsString()); // log.debug("onTransactionConfidenceChanged newTransaction " + newTransaction.getHashAsString());
} }
@ -123,8 +127,10 @@ public class ConfidenceDisplay
public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{ {
if (tx.getHashAsString().equals(transaction.getHashAsString())) if (tx.getHashAsString().equals(transaction.getHashAsString()))
{
updateBalance(newBalance); updateBalance(newBalance);
} }
}
@Override @Override
public void onReorganize(Wallet wallet) public void onReorganize(Wallet wallet)
@ -155,8 +161,10 @@ public class ConfidenceDisplay
progressIndicator.setProgress(0); progressIndicator.setProgress(0);
confirmationLabel.setText(""); confirmationLabel.setText("");
if (balanceTextField != null) if (balanceTextField != null)
{
balanceTextField.setText(""); balanceTextField.setText("");
} }
}
private void updateBalance(BigInteger balance) private void updateBalance(BigInteger balance)
{ {
@ -183,12 +191,16 @@ public class ConfidenceDisplay
} }
} }
if (latestTransaction != null && (transaction == null || latestTransaction.getHashAsString().equals(transaction.getHashAsString()))) if (latestTransaction != null && (transaction == null || latestTransaction.getHashAsString().equals(transaction.getHashAsString())))
{
updateConfidence(latestTransaction); updateConfidence(latestTransaction);
} }
}
if (balanceTextField != null) if (balanceTextField != null)
{
balanceTextField.setText(BtcFormatter.formatSatoshis(balance)); balanceTextField.setText(BtcFormatter.formatSatoshis(balance));
} }
}
private void updateConfidence(Transaction tx) private void updateConfidence(Transaction tx)
{ {

View file

@ -29,9 +29,13 @@ public class Country implements Serializable
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if (!(obj instanceof Country)) if (!(obj instanceof Country))
{
return false; return false;
}
if (obj == this) if (obj == this)
{
return true; return true;
}
final Country other = (Country) obj; final Country other = (Country) obj;
return code.equals(other.getCode()); return code.equals(other.getCode());

View file

@ -7,211 +7,17 @@ import java.util.stream.Collectors;
public class CountryUtil public class CountryUtil
{ {
private static final String[] countryCodes = new String[]{"AE", private static final String[] countryCodes = new String[]{"AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH", "BO", "BR", "BY", "CA", "CH", "CL", "CN", "CO", "CR", "CS", "CU", "CY", "CZ",
"AL", "DE", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JO", "JP", "KR", "KW", "LB", "LT", "LU",
"AR", "LV", "LY", "MA", "ME", "MK", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PR", "PT", "PY", "QA", "RO", "RS", "RU", "SA", "SD", "SE", "SG", "SI", "SK", "SV",
"AT", "SY", "TH", "TN", "TR", "TW", "UA", "US", "UY", "VE", "VN", "YE", "ZA"};
"AU",
"BA",
"BE",
"BG",
"BH",
"BO",
"BR",
"BY",
"CA",
"CH",
"CL",
"CN",
"CO",
"CR",
"CS",
"CU",
"CY",
"CZ",
"DE",
"DK",
"DO",
"DZ",
"EC",
"EE",
"EG",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HR",
"HU",
"ID",
"IE",
"IL",
"IN",
"IQ",
"IS",
"IT",
"JO",
"JP",
"KR",
"KW",
"LB",
"LT",
"LU",
"LV",
"LY",
"MA",
"ME",
"MK",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"OM",
"PA",
"PE",
"PH",
"PL",
"PR",
"PT",
"PY",
"QA",
"RO",
"RS",
"RU",
"SA",
"SD",
"SE",
"SG",
"SI",
"SK",
"SV",
"SY",
"TH",
"TN",
"TR",
"TW",
"UA",
"US",
"UY",
"VE",
"VN",
"YE",
"ZA"
};
private static final List<String> countryCodeList = Arrays.asList(countryCodes); private static final List<String> countryCodeList = Arrays.asList(countryCodes);
private static final String[] regionCodes = new String[]{ private static final String[] regionCodes = new String[]{"AS", "EU", "SA", "EU", "OC", "EU", "EU", "EU", "AS", "SA", "SA", "EU", "NA", "EU", "SA", "AS", "SA", "NA", "EU", "NA", "AS", "EU",
"AS", "EU", "EU", "NA", "AF", "SA", "EU", "AF", "EU", "EU", "EU", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "AS", "EU", "AS", "AS", "AS", "EU", "EU", "AS", "AS", "AS", "AS", "AS", "EU", "EU",
"EU", "EU", "AF", "AF", "EU", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "OC", "AS", "NA", "SA", "AS", "EU", "NA", "EU", "SA", "AS", "EU", "EU", "EU", "AS", "AF", "EU", "AS", "EU", "EU", "NA",
"SA", "AS", "AS", "AF", "AS", "AS", "EU", "NA", "SA", "SA", "AS", "AS", "AF"};
"EU",
"OC",
"EU",
"EU",
"EU",
"AS",
"SA",
"SA",
"EU",
"NA",
"EU",
"SA",
"AS",
"SA",
"NA",
"EU",
"NA",
"AS",
"EU",
"EU",
"EU",
"NA",
"AF",
"SA",
"EU",
"AF",
"EU",
"EU",
"EU",
"EU",
"EU",
"NA",
"AS",
"NA",
"EU",
"EU",
"AS",
"EU",
"AS",
"AS",
"AS",
"EU",
"EU",
"AS",
"AS",
"AS",
"AS",
"AS",
"EU",
"EU",
"EU",
"AF",
"AF",
"EU",
"EU",
"EU",
"NA",
"AS",
"NA",
"EU",
"EU",
"OC",
"AS",
"NA",
"SA",
"AS",
"EU",
"NA",
"EU",
"SA",
"AS",
"EU",
"EU",
"EU",
"AS",
"AF",
"EU",
"AS",
"EU",
"EU",
"NA",
"AS",
"AS",
"AF",
"AS",
"AS",
"EU",
"NA",
"SA",
"SA",
"AS",
"AS",
"AF"
};
private static final List<String> regionCodeList = Arrays.asList(regionCodes); private static final List<String> regionCodeList = Arrays.asList(regionCodes);
private static final String[][] regionCodeToName = new String[][]{ private static final String[][] regionCodeToName = new String[][]{{"NA", "North America"}, {"SA", "South America"}, {"AF", "Africa"}, {"EU", "Europe"}, {"AS", "Asia"}, {"OC", "Oceania"}};
{"NA", "North America"},
{"SA", "South America"},
{"AF", "Africa"},
{"EU", "Europe"},
{"AS", "Asia"},
{"OC", "Oceania"}
};
public static List<Region> getAllRegions() public static List<Region> getAllRegions()
@ -279,8 +85,10 @@ public class CountryUtil
for (final String[] regionName : regionCodeToName) for (final String[] regionName : regionCodeToName)
{ {
if (regionName[0].equals(regionCode)) if (regionName[0].equals(regionCode))
{
return regionName[1]; return regionName[1];
} }
}
return regionCode; return regionCode;
} }
@ -310,9 +118,13 @@ public class CountryUtil
private static String getRegionCode(String countryCode) private static String getRegionCode(String countryCode)
{ {
if (!countryCode.isEmpty() && countryCodeList.contains(countryCode)) if (!countryCode.isEmpty() && countryCodeList.contains(countryCode))
{
return regionCodeList.get(countryCodeList.indexOf(countryCode)); return regionCodeList.get(countryCodeList.indexOf(countryCode));
}
else else
{
return "Undefined"; return "Undefined";
} }
}
} }

View file

@ -26,9 +26,13 @@ public class Region implements Serializable
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if (!(obj instanceof Region)) if (!(obj instanceof Region))
{
return false; return false;
}
if (obj == this) if (obj == this)
{
return true; return true;
}
Region other = (Region) obj; Region other = (Region) obj;
return code.equals(other.getCode()); return code.equals(other.getCode());

View file

@ -72,9 +72,13 @@ public class MessageFacade
{ {
int port = Bindings.MAX_PORT - Math.abs(new Random().nextInt()) % (Bindings.MAX_PORT - Bindings.MIN_DYN_PORT); int port = Bindings.MAX_PORT - Math.abs(new Random().nextInt()) % (Bindings.MAX_PORT - Bindings.MIN_DYN_PORT);
if (BitSquare.ID.contains("taker")) if (BitSquare.ID.contains("taker"))
{
port = 4501; port = 4501;
}
else if (BitSquare.ID.contains("offerer")) else if (BitSquare.ID.contains("offerer"))
{
port = 4500; port = 4500;
}
try try
{ {
@ -93,8 +97,10 @@ public class MessageFacade
public void shutDown() public void shutDown()
{ {
if (myPeer != null) if (myPeer != null)
{
myPeer.shutdown(); myPeer.shutdown();
} }
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -224,12 +230,15 @@ public class MessageFacade
public void operationComplete(BaseFuture baseFuture) throws Exception public void operationComplete(BaseFuture baseFuture) throws Exception
{ {
if (sendFuture.isSuccess()) if (sendFuture.isSuccess())
{
Platform.runLater(() -> listener.onResult()); Platform.runLater(() -> listener.onResult());
}
else else
{
Platform.runLater(() -> listener.onFailed()); Platform.runLater(() -> listener.onFailed());
} }
} }
); });
} }
@ -319,8 +328,10 @@ public class MessageFacade
private void onArbitratorsReceived(Map<Number160, Data> dataMap, boolean success) private void onArbitratorsReceived(Map<Number160, Data> dataMap, boolean success)
{ {
for (ArbitratorListener arbitratorListener : arbitratorListeners) for (ArbitratorListener arbitratorListener : arbitratorListeners)
{
arbitratorListener.onArbitratorsReceived(dataMap, success); arbitratorListener.onArbitratorsReceived(dataMap, success);
} }
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Check dirty flag for a location key // Check dirty flag for a location key
@ -346,9 +357,11 @@ public class MessageFacade
{ {
Object object = data.getObject(); Object object = data.getObject();
if (object instanceof Long) if (object instanceof Long)
{
Platform.runLater(() -> onGetDirtyFlag((Long) object)); Platform.runLater(() -> onGetDirtyFlag((Long) object));
} }
} }
}
@Override @Override
public void exceptionCaught(Throwable t) throws Exception public void exceptionCaught(Throwable t) throws Exception
@ -366,10 +379,14 @@ public class MessageFacade
isDirty.setValue(!isDirty.get()); isDirty.setValue(!isDirty.get());
} }
if (lastTimeStamp > 0) if (lastTimeStamp > 0)
{
lastTimeStamp = timeStamp; lastTimeStamp = timeStamp;
}
else else
{
lastTimeStamp++; lastTimeStamp++;
} }
}
private Number160 getDirtyLocationKey(Number160 locationKey) private Number160 getDirtyLocationKey(Number160 locationKey)
{ {
@ -634,9 +651,13 @@ public class MessageFacade
{ {
myPeer.setObjectDataReply((sender, request) -> { myPeer.setObjectDataReply((sender, request) -> {
if (!sender.equals(myPeer.getPeerAddress())) if (!sender.equals(myPeer.getPeerAddress()))
{
Platform.runLater(() -> onMessage(request, sender)); Platform.runLater(() -> onMessage(request, sender));
}
else else
{
log.error("Received msg from myself. That should never happen."); log.error("Received msg from myself. That should never happen.");
}
//noinspection ReturnOfNull //noinspection ReturnOfNull
return null; return null;
}); });

View file

@ -51,8 +51,10 @@ public class Settings implements Serializable
public void addAcceptedLanguageLocale(Locale locale) public void addAcceptedLanguageLocale(Locale locale)
{ {
if (!acceptedLanguageLocales.contains(locale)) if (!acceptedLanguageLocales.contains(locale))
{
acceptedLanguageLocales.add(locale); acceptedLanguageLocales.add(locale);
} }
}
public void removeAcceptedLanguageLocale(Locale item) public void removeAcceptedLanguageLocale(Locale item)
{ {
@ -62,8 +64,10 @@ public class Settings implements Serializable
public void addAcceptedCountry(Country locale) public void addAcceptedCountry(Country locale)
{ {
if (!acceptedCountryLocales.contains(locale)) if (!acceptedCountryLocales.contains(locale))
{
acceptedCountryLocales.add(locale); acceptedCountryLocales.add(locale);
} }
}
public void removeAcceptedCountry(Country item) public void removeAcceptedCountry(Country item)
{ {
@ -73,8 +77,10 @@ public class Settings implements Serializable
public void addAcceptedArbitrator(Arbitrator arbitrator) public void addAcceptedArbitrator(Arbitrator arbitrator)
{ {
if (!acceptedArbitrators.contains(arbitrator)) if (!acceptedArbitrators.contains(arbitrator))
{
acceptedArbitrators.add(arbitrator); acceptedArbitrators.add(arbitrator);
} }
}
public void removeAcceptedArbitrator(Arbitrator item) public void removeAcceptedArbitrator(Arbitrator item)
{ {

View file

@ -237,10 +237,14 @@ public class Storage
// Work around an issue on Windows whereby you can't rename over existing files. // Work around an issue on Windows whereby you can't rename over existing files.
final File canonical = storageFile.getCanonicalFile(); final File canonical = storageFile.getCanonicalFile();
if (canonical.exists() && !canonical.delete()) if (canonical.exists() && !canonical.delete())
{
throw new IOException("Failed to delete canonical file for replacement with save"); throw new IOException("Failed to delete canonical file for replacement with save");
}
if (!tempFile.renameTo(canonical)) if (!tempFile.renameTo(canonical))
{
throw new IOException("Failed to rename " + tempFile + " to " + canonical); throw new IOException("Failed to rename " + tempFile + " to " + canonical);
} }
}
else if (!tempFile.renameTo(storageFile)) else if (!tempFile.renameTo(storageFile))
{ {
throw new IOException("Failed to rename " + tempFile + " to " + storageFile); throw new IOException("Failed to rename " + tempFile + " to " + storageFile);
@ -255,9 +259,11 @@ public class Storage
{ {
log.warn("Temp file still exists after failed save."); log.warn("Temp file still exists after failed save.");
if (!tempFile.delete()) if (!tempFile.delete())
{
log.warn("Cannot delete temp file."); log.warn("Cannot delete temp file.");
} }
} }
}
} catch (IOException e) } catch (IOException e)
{ {
e.printStackTrace(); e.printStackTrace();

View file

@ -12,15 +12,8 @@ import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
import io.bitsquare.msg.listeners.TakeOfferRequestListener; import io.bitsquare.msg.listeners.TakeOfferRequestListener;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.messages.offerer.*; import io.bitsquare.trade.protocol.offerer.*;
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.taker.*;
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.messages.taker.RequestTakeOfferMessage;
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocol;
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocolListener;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocol;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocolListener;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
@ -49,8 +42,10 @@ public class Trading
private final CryptoFacade cryptoFacade; private final CryptoFacade cryptoFacade;
private final List<TakeOfferRequestListener> takeOfferRequestListeners = new ArrayList<>(); private final List<TakeOfferRequestListener> takeOfferRequestListeners = new ArrayList<>();
private final Map<String, TakerAsSellerProtocol> takerAsSellerProtocolMap = new HashMap<>();
private final Map<String, OffererAsBuyerProtocol> offererAsBuyerProtocolMap = new HashMap<>(); //TODO store TakerAsSellerProtocol in trade
private final Map<String, ProtocolForTakerAsSeller> takerAsSellerProtocolMap = new HashMap<>();
private final Map<String, ProtocolForOffererAsBuyer> offererAsBuyerProtocolMap = new HashMap<>();
private final StringProperty newTradeProperty = new SimpleStringProperty(); private final StringProperty newTradeProperty = new SimpleStringProperty();
@ -65,12 +60,7 @@ public class Trading
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public Trading(User user, public Trading(User user, Storage storage, MessageFacade messageFacade, BlockChainFacade blockChainFacade, WalletFacade walletFacade, CryptoFacade cryptoFacade)
Storage storage,
MessageFacade messageFacade,
BlockChainFacade blockChainFacade,
WalletFacade walletFacade,
CryptoFacade cryptoFacade)
{ {
this.user = user; this.user = user;
this.storage = storage; this.storage = storage;
@ -81,15 +71,23 @@ public class Trading
Object offersObject = storage.read(storageKey + ".offers"); Object offersObject = storage.read(storageKey + ".offers");
if (offersObject instanceof HashMap) if (offersObject instanceof HashMap)
{
offers = (Map<String, Offer>) offersObject; offers = (Map<String, Offer>) offersObject;
}
else else
{
offers = new HashMap<>(); offers = new HashMap<>();
}
Object tradesObject = storage.read(storageKey + ".trades"); Object tradesObject = storage.read(storageKey + ".trades");
if (tradesObject instanceof HashMap) if (tradesObject instanceof HashMap)
{
trades = (Map<String, Trade>) tradesObject; trades = (Map<String, Trade>) tradesObject;
}
else else
{
trades = new HashMap<>(); trades = new HashMap<>();
}
messageFacade.addIncomingTradeMessageListener(this::onIncomingTradeMessage); messageFacade.addIncomingTradeMessageListener(this::onIncomingTradeMessage);
} }
@ -127,7 +125,9 @@ public class Trading
public void addOffer(Offer offer) throws IOException public void addOffer(Offer offer) throws IOException
{ {
if (offers.containsKey(offer.getId())) if (offers.containsKey(offer.getId()))
{
throw new IllegalStateException("offers contains already an offer with the ID " + offer.getId()); throw new IllegalStateException("offers contains already an offer with the ID " + offer.getId());
}
offers.put(offer.getId(), offer); offers.put(offer.getId(), offer);
saveOffers(); saveOffers();
@ -138,7 +138,9 @@ public class Trading
public void removeOffer(Offer offer) public void removeOffer(Offer offer)
{ {
if (!offers.containsKey(offer.getId())) if (!offers.containsKey(offer.getId()))
{
throw new IllegalStateException("offers does not contain the offer with the ID " + offer.getId()); throw new IllegalStateException("offers does not contain the offer with the ID " + offer.getId());
}
offers.remove(offer.getId()); offers.remove(offer.getId());
saveOffers(); saveOffers();
@ -146,14 +148,14 @@ public class Trading
messageFacade.removeOffer(offer); messageFacade.removeOffer(offer);
} }
public Trade takeOffer(BigInteger amount, Offer offer, TakerAsSellerProtocolListener listener) public Trade takeOffer(BigInteger amount, Offer offer, ProtocolForTakerAsSellerListener listener)
{ {
Trade trade = createTrade(offer); Trade trade = createTrade(offer);
trade.setTradeAmount(amount); trade.setTradeAmount(amount);
TakerAsSellerProtocol takerAsSellerProtocol = new TakerAsSellerProtocol(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user); ProtocolForTakerAsSeller protocolForTakerAsSeller = new ProtocolForTakerAsSeller(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
takerAsSellerProtocolMap.put(trade.getId(), takerAsSellerProtocol); takerAsSellerProtocolMap.put(trade.getId(), protocolForTakerAsSeller);
takerAsSellerProtocol.start(); protocolForTakerAsSeller.start();
return trade; return trade;
} }
@ -166,7 +168,9 @@ public class Trading
public Trade createTrade(Offer offer) public Trade createTrade(Offer offer)
{ {
if (trades.containsKey(offer.getId())) if (trades.containsKey(offer.getId()))
{
throw new IllegalStateException("trades contains already an trade with the ID " + offer.getId()); throw new IllegalStateException("trades contains already an trade with the ID " + offer.getId());
}
Trade trade = new Trade(offer); Trade trade = new Trade(offer);
trades.put(offer.getId(), trade); trades.put(offer.getId(), trade);
@ -181,7 +185,9 @@ public class Trading
public void removeTrade(Trade trade) public void removeTrade(Trade trade)
{ {
if (!trades.containsKey(trade.getId())) if (!trades.containsKey(trade.getId()))
{
throw new IllegalStateException("trades does not contain the trade with the ID " + trade.getId()); throw new IllegalStateException("trades does not contain the trade with the ID " + trade.getId());
}
trades.remove(trade.getId()); trades.remove(trade.getId());
saveTrades(); saveTrades();
@ -205,7 +211,14 @@ public class Trading
Trade trade = createTrade(offer); Trade trade = createTrade(offer);
pendingTrade = trade; pendingTrade = trade;
OffererAsBuyerProtocol offererAsBuyerProtocol = new OffererAsBuyerProtocol(trade, sender, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user, new OffererAsBuyerProtocolListener() ProtocolForOffererAsBuyer protocolForOffererAsBuyer = new ProtocolForOffererAsBuyer(trade,
sender,
messageFacade,
walletFacade,
blockChainFacade,
cryptoFacade,
user,
new ProtocolForOffererAsBuyerListener()
{ {
@Override @Override
public void onOfferAccepted(Offer offer) public void onOfferAccepted(Offer offer)
@ -228,33 +241,36 @@ public class Trading
@Override @Override
public void onPayoutTxPublished(String payoutTxAsHex) public void onPayoutTxPublished(String payoutTxAsHex)
{ {
Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex)); Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(),
Utils.parseAsHexOrBase58(payoutTxAsHex));
trade.setPayoutTransaction(payoutTx); trade.setPayoutTransaction(payoutTx);
trade.setState(Trade.State.COMPLETED); trade.setState(Trade.State.COMPLETED);
log.debug("trading onPayoutTxPublishedMessage"); log.debug("trading onPayoutTxPublishedMessage");
} }
@Override @Override
public void onFault(Throwable throwable, OffererAsBuyerProtocol.State state) public void onFault(Throwable throwable, ProtocolForOffererAsBuyer.State state)
{ {
log.error("Error while executing trade process at state: " + state + " / " + throwable); log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable); Popups.openErrorPopup("Error while executing trade process",
"Error while executing trade process at state: " + state + " / " +
throwable);
} }
@Override @Override
public void onWaitingForPeerResponse(OffererAsBuyerProtocol.State state) public void onWaitingForPeerResponse(ProtocolForOffererAsBuyer.State state)
{ {
log.debug("Waiting for peers response at state " + state); log.debug("Waiting for peers response at state " + state);
} }
@Override @Override
public void onCompleted(OffererAsBuyerProtocol.State state) public void onCompleted(ProtocolForOffererAsBuyer.State state)
{ {
log.debug("Trade protocol completed at state " + state); log.debug("Trade protocol completed at state " + state);
} }
@Override @Override
public void onWaitingForUserInteraction(OffererAsBuyerProtocol.State state) public void onWaitingForUserInteraction(ProtocolForOffererAsBuyer.State state)
{ {
log.debug("Waiting for UI activity at state " + state); log.debug("Waiting for UI activity at state " + state);
} }
@ -267,8 +283,18 @@ public class Trading
} }
}); });
this.offererAsBuyerProtocolMap.put(trade.getId(), offererAsBuyerProtocol);
offererAsBuyerProtocol.start(); if (!offererAsBuyerProtocolMap.containsKey(trade.getId()))
{
offererAsBuyerProtocolMap.put(trade.getId(), protocolForOffererAsBuyer);
}
else
{
// We don't store the protocol in case we have already a pending offer. The protocol is only temporary used to reply with a reject message.
log.trace("offererAsBuyerProtocol not stored as offer is already pending.");
}
protocolForOffererAsBuyer.start();
} }
else else
{ {
@ -305,13 +331,9 @@ public class Trading
createOffererAsBuyerProtocol(tradeId, sender); createOffererAsBuyerProtocol(tradeId, sender);
takeOfferRequestListeners.stream().forEach(e -> e.onTakeOfferRequested(tradeId, sender)); takeOfferRequestListeners.stream().forEach(e -> e.onTakeOfferRequested(tradeId, sender));
} }
else if (tradeMessage instanceof AcceptTakeOfferRequestMessage) else if (tradeMessage instanceof RespondToTakeOfferRequestMessage)
{ {
takerAsSellerProtocolMap.get(tradeId).onAcceptTakeOfferRequestMessage(); takerAsSellerProtocolMap.get(tradeId).onRespondToTakeOfferRequestMessage((RespondToTakeOfferRequestMessage) tradeMessage);
}
else if (tradeMessage instanceof RejectTakeOfferRequestMessage)
{
takerAsSellerProtocolMap.get(tradeId).onRejectTakeOfferRequestMessage();
} }
else if (tradeMessage instanceof TakeOfferFeePayedMessage) else if (tradeMessage instanceof TakeOfferFeePayedMessage)
{ {
@ -398,8 +420,12 @@ public class Trading
public Trade getTrade(String tradeId) public Trade getTrade(String tradeId)
{ {
if (trades.containsKey(tradeId)) if (trades.containsKey(tradeId))
{
return trades.get(trades); return trades.get(trades);
}
else else
{
return null; return null;
} }
} }
}

View file

@ -70,10 +70,14 @@ public class OrderBook implements OrderBookListener
public void loadOffers() public void loadOffers()
{ {
if (user.getCurrentBankAccount() != null) if (user.getCurrentBankAccount() != null)
{
messageFacade.getOffers(user.getCurrentBankAccount().getCurrency().getCurrencyCode()); messageFacade.getOffers(user.getCurrentBankAccount().getCurrency().getCurrencyCode());
}
else else
{
messageFacade.getOffers(CurrencyUtil.getDefaultCurrency().getCurrencyCode()); messageFacade.getOffers(CurrencyUtil.getDefaultCurrency().getCurrencyCode());
} }
}
public void removeOffer(Offer offer) public void removeOffer(Offer offer)
{ {
@ -86,10 +90,10 @@ public class OrderBook implements OrderBookListener
Offer offer = orderBookListItem.getOffer(); Offer offer = orderBookListItem.getOffer();
BankAccount currentBankAccount = user.getCurrentBankAccount(); BankAccount currentBankAccount = user.getCurrentBankAccount();
if (orderBookFilter == null if (orderBookFilter == null || currentBankAccount == null || orderBookFilter.getDirection() == null)
|| currentBankAccount == null {
|| orderBookFilter.getDirection() == null)
return false; return false;
}
// The users current bank account currency must match the offer currency (1 to 1) // The users current bank account currency must match the offer currency (1 to 1)
boolean currencyResult = currentBankAccount.getCurrency().equals(offer.getCurrency()); boolean currencyResult = currentBankAccount.getCurrency().equals(offer.getCurrency());
@ -104,7 +108,9 @@ public class OrderBook implements OrderBookListener
// The requested amount must be lower or equal then the offer amount // The requested amount must be lower or equal then the offer amount
boolean amountResult = true; boolean amountResult = true;
if (orderBookFilter.getAmount() > 0) if (orderBookFilter.getAmount() > 0)
{
amountResult = orderBookFilter.getAmount() <= offer.getAmount().doubleValue(); amountResult = orderBookFilter.getAmount() <= offer.getAmount().doubleValue();
}
// The requested trade direction must be opposite of the offerList trade direction // The requested trade direction must be opposite of the offerList trade direction
boolean directionResult = !orderBookFilter.getDirection().equals(offer.getDirection()); boolean directionResult = !orderBookFilter.getDirection().equals(offer.getDirection());
@ -114,23 +120,21 @@ public class OrderBook implements OrderBookListener
if (orderBookFilter.getPrice() > 0) if (orderBookFilter.getPrice() > 0)
{ {
if (offer.getDirection() == Direction.SELL) if (offer.getDirection() == Direction.SELL)
{
priceResult = orderBookFilter.getPrice() >= offer.getPrice(); priceResult = orderBookFilter.getPrice() >= offer.getPrice();
}
else else
{
priceResult = orderBookFilter.getPrice() <= offer.getPrice(); priceResult = orderBookFilter.getPrice() <= offer.getPrice();
} }
}
// The arbitrator defined in the offer must match one of the accepted arbitrators defined in the settings (1 to n) // The arbitrator defined in the offer must match one of the accepted arbitrators defined in the settings (1 to n)
boolean arbitratorResult = arbitratorInList(offer.getArbitrator(), settings.getAcceptedArbitrators()); boolean arbitratorResult = arbitratorInList(offer.getArbitrator(), settings.getAcceptedArbitrators());
//noinspection UnnecessaryLocalVariable //noinspection UnnecessaryLocalVariable
boolean result = currencyResult boolean result = currencyResult && countryResult && languageResult && amountResult && directionResult && priceResult && arbitratorResult;
&& countryResult
&& languageResult
&& amountResult
&& directionResult
&& priceResult
&& arbitratorResult;
/* /*
log.debug("result = " + result + log.debug("result = " + result +
@ -260,8 +264,10 @@ public class OrderBook implements OrderBookListener
for (Country country : list) for (Country country : list)
{ {
if (country.getCode().equals(countryToMatch.getCode())) if (country.getCode().equals(countryToMatch.getCode()))
{
return true; return true;
} }
}
return false; return false;
} }
@ -272,9 +278,11 @@ public class OrderBook implements OrderBookListener
for (Locale locale2 : list1) for (Locale locale2 : list1)
{ {
if (locale1.getLanguage().equals(locale2.getLanguage())) if (locale1.getLanguage().equals(locale2.getLanguage()))
{
return true; return true;
} }
} }
}
return false; return false;
} }
@ -287,7 +295,9 @@ public class OrderBook implements OrderBookListener
try try
{ {
if (arbitrator.getId().equals(arbitratorToMatch.getId())) if (arbitrator.getId().equals(arbitratorToMatch.getId()))
{
return true; return true;
}
} catch (Exception e) } catch (Exception e)
{ {
log.error(e.toString()); log.error(e.toString());

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.tasks; package io.bitsquare.trade.protocol;
public interface FaultHandler public interface FaultHandler
{ {

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.tasks; package io.bitsquare.trade.protocol;
public interface ResultHandler public interface ResultHandler
{ {

View file

@ -1,22 +0,0 @@
package io.bitsquare.trade.protocol.messages.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
public class AcceptTakeOfferRequestMessage implements Serializable, TradeMessage
{
private static final long serialVersionUID = 6177387534087739018L;
private final String tradeId;
public AcceptTakeOfferRequestMessage(String tradeId)
{
this.tradeId = tradeId;
}
@Override
public String getTradeId()
{
return tradeId;
}
}

View file

@ -1,21 +0,0 @@
package io.bitsquare.trade.protocol.messages.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
public class RejectTakeOfferRequestMessage implements Serializable, TradeMessage
{
private static final long serialVersionUID = -8088557759642128139L;
private final String tradeId;
public RejectTakeOfferRequestMessage(String tradeId)
{
this.tradeId = tradeId;
}
@Override
public String getTradeId()
{
return tradeId;
}
}

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.offerer; package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
import java.io.Serializable; import java.io.Serializable;
@ -16,7 +16,8 @@ public class BankTransferInitedMessage implements Serializable, TradeMessage
private BigInteger takerPaybackAmount; private BigInteger takerPaybackAmount;
private String offererPayoutAddress; private String offererPayoutAddress;
public BankTransferInitedMessage(String tradeId, String depositTxAsHex, public BankTransferInitedMessage(String tradeId,
String depositTxAsHex,
String offererSignatureR, String offererSignatureR,
String offererSignatureS, String offererSignatureS,
BigInteger offererPaybackAmount, BigInteger offererPaybackAmount,

View file

@ -1,10 +1,10 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.InsufficientMoneyException; import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction; import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils; import com.google.bitcoin.core.Utils;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.FaultHandler;
import java.math.BigInteger; import java.math.BigInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -24,11 +24,7 @@ public class CreateDepositTx
try try
{ {
String offererPubKey = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString(); String offererPubKey = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
Transaction transaction = walletFacade.offererCreatesMSTxAndAddPayment(collateralAmount, Transaction transaction = walletFacade.offererCreatesMSTxAndAddPayment(collateralAmount, offererPubKey, takerMultiSigPubKey, arbitratorPubKeyAsHex, tradeId);
offererPubKey,
takerMultiSigPubKey,
arbitratorPubKeyAsHex,
tradeId);
String preparedOffererDepositTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize()); String preparedOffererDepositTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex(); long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex();

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.offerer; package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
import java.io.Serializable; import java.io.Serializable;

View file

@ -0,0 +1,44 @@
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.FaultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HandleTakeOfferRequest
{
private static final Logger log = LoggerFactory.getLogger(HandleTakeOfferRequest.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade.State tradeState, String tradeId)
{
boolean takeOfferRequestAccepted = tradeState == Trade.State.OPEN;
if (!takeOfferRequestAccepted)
{
log.info("Received take offer request but the offer not marked as open anymore.");
}
messageFacade.sendTradeMessage(peerAddress, new RespondToTakeOfferRequestMessage(tradeId, takeOfferRequestAccepted), new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RespondToTakeOfferRequestMessage successfully arrived at peer");
resultHandler.onResult(takeOfferRequestAccepted);
}
@Override
public void onFailed()
{
log.error("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer"));
}
});
}
public interface ResultHandler
{
void onResult(boolean takeOfferRequestAccepted);
}
}

View file

@ -10,368 +10,39 @@ import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Contract; import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.taker.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage; import io.bitsquare.trade.protocol.taker.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage; import io.bitsquare.trade.protocol.taker.TakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.tasks.offerer.*;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import java.math.BigInteger; import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.*;
import static com.google.common.base.Preconditions.checkState;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
/** /**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer. * Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer.
* That class handles the role of the offerer as the Bitcoin buyer. * <p>
* This class handles the role of the offerer as the Bitcoin buyer.
* <p>
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling. * It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing. * Any data from incoming messages need to be validated before further processing.
*/ */
public class OffererAsBuyerProtocol public class ProtocolForOffererAsBuyer
{ {
private static final Logger log = LoggerFactory.getLogger(OffererAsBuyerProtocol.class); private static final Logger log = LoggerFactory.getLogger(ProtocolForOffererAsBuyer.class);
public final PeerAddress peerAddress; private final String arbitratorPubKey;
// provided data private final BigInteger collateral;
private final String id; private final BankAccount bankAccount;
private final Trade trade; private final String accountId;
private final OffererAsBuyerProtocolListener listener; private final BigInteger tradeAmount;
private final MessageFacade messageFacade; private final String messagePubKey;
private final WalletFacade walletFacade; private final ECKey accountKey;
private final BlockChainFacade blockChainFacade; private final String payoutAddress;
private final CryptoFacade cryptoFacade;
private final User user;
private final String tradeId;
private final Offer offer;
// data written/read by tasks
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
// data written by messages, read by tasks
private String takeOfferFeeTxId;
private String takerMultiSigPubKey;
private String takerPayoutAddress;
private String peersAccountId;
private BankAccount peersBankAccount;
private String takerMessagePubKey;
private String peersContractAsJson;
private String signedTakerDepositTxAsHex;
private String txConnOutAsHex;
private String txScriptSigAsHex;
private long takerTxOutIndex;
// private
private State state;
public OffererAsBuyerProtocol(Trade trade,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user,
OffererAsBuyerProtocolListener listener)
{
this.trade = trade;
this.peerAddress = peerAddress;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
this.user = user;
id = trade.getId();
tradeId = trade.getId();
offer = trade.getOffer();
state = State.Init;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public void start()
{
log.debug("start");
HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFault, peerAddress, messageFacade, trade.getState(), tradeId);
state = State.HandleTakeOfferRequest;
}
public void onResultHandleTakeOfferRequest(Trade.State tradeState)
{
log.debug("onResultHandleTakeOfferRequest");
trade.setState(tradeState);
messageFacade.removeOffer(offer);
listener.onOfferAccepted(offer);
listener.onWaitingForPeerResponse(state);
}
public void onTakeOfferFeePayedMessage(TakeOfferFeePayedMessage message)
{
log.debug("onTakeOfferFeePayedMessage");
// validation
checkState(state == State.HandleTakeOfferRequest);
checkNotNull(message);
String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
BigInteger tradeAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getTradeAmount()));
String takerMultiSigPubKey = nonEmptyStringOf(message.getTakerMultiSigPubKey());
// apply new state
state = State.onTakeOfferFeePayedMessage;
this.takeOfferFeeTxId = takeOfferFeeTxId;
this.takerMultiSigPubKey = takerMultiSigPubKey;
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
trade.setTradeAmount(tradeAmount);
// next task
VerifyTakeOfferFeePayment.run(this::onResultVerifyTakeOfferFeePayment, this::onFault, walletFacade, takeOfferFeeTxId);
state = State.VerifyTakeOfferFeePayment;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultVerifyTakeOfferFeePayment()
{
log.debug("onResultVerifyTakeOfferFeePayment");
BigInteger collateralAmount = trade.getCollateralAmount();
String arbitratorPubKeyAsHex = offer.getArbitrator().getPubKeyAsHex();
CreateDepositTx.run(this::onResultCreateDepositTx,
this::onFault,
walletFacade,
tradeId,
collateralAmount,
takerMultiSigPubKey,
arbitratorPubKeyAsHex);
state = State.CreateDepositTx;
}
public void onResultCreateDepositTx(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex)
{
log.debug("onResultCreateDepositTx");
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
this.offererTxOutIndex = offererTxOutIndex;
BankAccount bankAccount = user.getBankAccount(trade.getOffer().getBankAccountId());
String accountId = user.getAccountId();
RequestTakerDepositPayment.run(this::onResultRequestTakerDepositPayment,
this::onFault,
peerAddress,
messageFacade,
tradeId,
bankAccount,
accountId,
offererPubKey,
preparedOffererDepositTxAsHex,
offererTxOutIndex);
state = State.RequestTakerDepositPayment;
}
public void onResultRequestTakerDepositPayment()
{
log.debug("onResultRequestTakerDepositPayment");
listener.onWaitingForPeerResponse(state);
}
public void onRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message)
{
log.debug("onRequestOffererPublishDepositTxMessage");
// validation
checkState(state == State.RequestTakerDepositPayment);
checkNotNull(message);
String takerPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
String peersAccountId = nonEmptyStringOf(message.getAccountId());
BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
String takerMessagePubKey = nonEmptyStringOf(message.getTakerMessagePubKey());
String peersContractAsJson = nonEmptyStringOf(message.getContractAsJson());
String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// apply new state
state = State.onRequestOffererPublishDepositTxMessage;
this.takerPayoutAddress = takerPayoutAddress;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.takerMessagePubKey = takerMessagePubKey;
this.peersContractAsJson = peersContractAsJson;
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
this.txConnOutAsHex = txConnOutAsHex;
this.txScriptSigAsHex = txScriptSigAsHex;
this.takerTxOutIndex = takerTxOutIndex;
// next task
VerifyTakerAccount.run(this::onResultVerifyTakerAccount, this::onFault, blockChainFacade, peersAccountId, peersBankAccount);
state = State.VerifyTakerAccount;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultVerifyTakerAccount()
{
log.debug("onResultVerifyTakerAccount");
String accountId = user.getAccountId();
BigInteger tradeAmount = trade.getTradeAmount();
String messagePubKeyAsHex = user.getMessagePubKeyAsHex();
BankAccount bankAccount = user.getBankAccount(offer.getBankAccountId());
ECKey registrationKey = walletFacade.getRegistrationAddressInfo().getKey();
VerifyAndSignContract.run(this::onResultVerifyAndSignContract,
this::onFault,
cryptoFacade,
accountId,
tradeAmount,
takeOfferFeeTxId,
messagePubKeyAsHex,
offer,
peersAccountId,
bankAccount,
peersBankAccount,
takerMessagePubKey,
peersContractAsJson,
registrationKey);
state = State.VerifyAndSignContract;
}
public void onResultVerifyAndSignContract(Contract contract, String contractAsJson, String signature)
{
log.debug("onResultVerifyAndSignContract");
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
SignAndPublishDepositTx.run(this::onResultSignAndPublishDepositTx,
this::onFault,
walletFacade,
preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex);
state = State.SignAndPublishDepositTx;
}
public void onResultSignAndPublishDepositTx(Transaction transaction)
{
log.debug("onResultSignAndPublishDepositTx");
trade.setDepositTransaction(transaction);
listener.onDepositTxPublished(transaction.getHashAsString());
Transaction depositTransaction = trade.getDepositTransaction();
SendDepositTxIdToTaker.run(this::onResultSendDepositTxIdToTaker, this::onFault, peerAddress, messageFacade, tradeId, depositTransaction);
state = State.SendDepositTxIdToTaker;
}
public void onResultSendDepositTxIdToTaker()
{
log.debug("onResultSendDepositTxIdToTaker");
SetupListenerForBlockChainConfirmation.run(this::onResultSetupListenerForBlockChainConfirmation, this::onFault, trade.getDepositTransaction(), listener);
state = State.SetupListenerForBlockChainConfirmation;
}
public void onResultSetupListenerForBlockChainConfirmation()
{
log.debug("onResultSetupListenerForBlockChainConfirmation");
state = State.onResultSetupListenerForBlockChainConfirmation;
listener.onWaitingForUserInteraction(state);
}
// Triggered from UI event: Button click "Bank transfer inited"
public void onUIEventBankTransferInited()
{
log.debug("onUIEventBankTransferInited");
// validation
checkState(state == State.onResultSetupListenerForBlockChainConfirmation);
state = State.onUIEventBankTransferInited;
// next task
String depositTransactionId = trade.getDepositTransaction().getHashAsString();
String offererPayoutAddress = walletFacade.getAddressInfoByTradeID(tradeId).getAddressString();
BigInteger collateral = trade.getCollateralAmount();
BigInteger tradeAmount = trade.getTradeAmount();
SendSignedPayoutTx.run(this::onResultSendSignedPayoutTx, this::onFault, peerAddress, messageFacade, walletFacade, tradeId, takerPayoutAddress, offererPayoutAddress, depositTransactionId, collateral, tradeAmount);
state = State.SendSignedPayoutTx;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultSendSignedPayoutTx()
{
log.debug("onResultSendSignedPayoutTx");
listener.onWaitingForPeerResponse(state);
}
public void onPayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage)
{
log.debug("onPayoutTxPublishedMessage");
// validation
checkState(state == State.SendSignedPayoutTx);
String payoutTxAsHex = nonEmptyStringOf(tradeMessage.getPayoutTxAsHex());
state = State.onPayoutTxPublishedMessage;
// next task
listener.onPayoutTxPublished(payoutTxAsHex);
listener.onCompleted(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
public enum State public enum State
{ {
@ -397,4 +68,351 @@ public class OffererAsBuyerProtocol
onPayoutTxPublishedMessage onPayoutTxPublishedMessage
} }
private final Trade trade;
private final PeerAddress peerAddress;
private final MessageFacade messageFacade;
private final WalletFacade walletFacade;
private final BlockChainFacade blockChainFacade;
private final CryptoFacade cryptoFacade;
private final ProtocolForOffererAsBuyerListener listener;
private final String id;
private final String tradeId;
private final Offer offer;
private State state;
// data written/read by tasks
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
// data written by messages, read by tasks
private String takeOfferFeeTxId;
private String takerPubKey;
private String peersPayoutAddress;
private String peersAccountId;
private BankAccount peersBankAccount;
private String peersMessagePubKey;
private String peersContractAsJson;
private String signedTakerDepositTxAsHex;
private String txConnOutAsHex;
private String txScriptSigAsHex;
private long takerTxOutIndex;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ProtocolForOffererAsBuyer(Trade trade,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user,
ProtocolForOffererAsBuyerListener listener)
{
this.trade = trade;
this.peerAddress = peerAddress;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
id = trade.getId();
tradeId = trade.getId();
offer = trade.getOffer();
arbitratorPubKey = offer.getArbitrator().getPubKeyAsHex();
collateral = trade.getCollateralAmount();
bankAccount = user.getBankAccount(trade.getOffer().getBankAccountId());
accountId = user.getAccountId();
tradeAmount = trade.getTradeAmount();
messagePubKey = user.getMessagePubKeyAsHex();
accountKey = walletFacade.getRegistrationAddressInfo().getKey();
payoutAddress = walletFacade.getAddressInfoByTradeID(tradeId).getAddressString();
state = State.Init;
}
public void start()
{
log.debug("start called ");
HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFault, peerAddress, messageFacade, trade.getState(), tradeId);
state = State.HandleTakeOfferRequest;
}
public void onResultHandleTakeOfferRequest(boolean takeOfferRequestAccepted)
{
log.debug("onResultHandleTakeOfferRequest called ");
if (takeOfferRequestAccepted)
{
trade.setState(Trade.State.ACCEPTED);
messageFacade.removeOffer(offer);
listener.onOfferAccepted(offer);
listener.onWaitingForPeerResponse(state);
}
else
{
log.info("Finish here as we have already the offer accepted.");
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onTakeOfferFeePayedMessage(@NotNull TakeOfferFeePayedMessage message)
{
log.debug("onTakeOfferFeePayedMessage called ");
// validation
checkState(state == State.HandleTakeOfferRequest);
checkArgument(tradeId.equals(message.getTradeId()));
String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
BigInteger tradeAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getTradeAmount()));
String takerPubKey = nonEmptyStringOf(message.getTakerPubKey());
// apply new state
state = State.onTakeOfferFeePayedMessage;
this.takeOfferFeeTxId = takeOfferFeeTxId;
this.takerPubKey = takerPubKey;
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
trade.setTradeAmount(tradeAmount);
// next task
VerifyTakeOfferFeePayment.run(this::onResultVerifyTakeOfferFeePayment, this::onFault, walletFacade, this.takeOfferFeeTxId);
state = State.VerifyTakeOfferFeePayment;
}
public void onResultVerifyTakeOfferFeePayment()
{
log.debug("onResultVerifyTakeOfferFeePayment called ");
CreateDepositTx.run(this::onResultCreateDepositTx, this::onFault, walletFacade, tradeId, collateral, takerPubKey, arbitratorPubKey);
state = State.CreateDepositTx;
}
public void onResultCreateDepositTx(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex)
{
log.debug("onResultCreateDepositTx called ");
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
this.offererTxOutIndex = offererTxOutIndex;
RequestTakerDepositPayment.run(this::onResultRequestTakerDepositPayment,
this::onFault,
peerAddress,
messageFacade,
tradeId,
bankAccount,
accountId,
offererPubKey,
preparedOffererDepositTxAsHex,
offererTxOutIndex);
state = State.RequestTakerDepositPayment;
}
public void onResultRequestTakerDepositPayment()
{
log.debug("onResultRequestTakerDepositPayment called ");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message)
{
log.debug("onRequestOffererPublishDepositTxMessage called ");
// validation
checkState(state == State.RequestTakerDepositPayment);
checkArgument(tradeId.equals(message.getTradeId()));
String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
String peersMessagePubKey = nonEmptyStringOf(message.getTakerMessagePubKey());
String peersContractAsJson = nonEmptyStringOf(message.getTakerContractAsJson());
String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// apply new state
state = State.onRequestOffererPublishDepositTxMessage;
this.peersPayoutAddress = peersPayoutAddress;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.peersMessagePubKey = peersMessagePubKey;
this.peersContractAsJson = peersContractAsJson;
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
this.txConnOutAsHex = txConnOutAsHex;
this.txScriptSigAsHex = txScriptSigAsHex;
this.takerTxOutIndex = takerTxOutIndex;
// next task
VerifyTakerAccount.run(this::onResultVerifyTakerAccount, this::onFault, blockChainFacade, this.peersAccountId, this.peersBankAccount);
state = State.VerifyTakerAccount;
}
public void onResultVerifyTakerAccount()
{
log.debug("onResultVerifyTakerAccount called ");
VerifyAndSignContract.run(this::onResultVerifyAndSignContract,
this::onFault,
cryptoFacade,
accountId,
tradeAmount,
takeOfferFeeTxId,
messagePubKey,
offer,
peersAccountId,
bankAccount,
peersBankAccount,
peersMessagePubKey,
peersContractAsJson,
accountKey);
state = State.VerifyAndSignContract;
}
public void onResultVerifyAndSignContract(Contract contract, String contractAsJson, String signature)
{
log.debug("onResultVerifyAndSignContract called ");
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
SignAndPublishDepositTx.run(this::onResultSignAndPublishDepositTx,
this::onFault,
walletFacade,
preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex);
state = State.SignAndPublishDepositTx;
}
public void onResultSignAndPublishDepositTx(Transaction depositTransaction)
{
log.debug("onResultSignAndPublishDepositTx called ");
trade.setDepositTransaction(depositTransaction);
listener.onDepositTxPublished(depositTransaction.getHashAsString());
SendDepositTxIdToTaker.run(this::onResultSendDepositTxIdToTaker, this::onFault, peerAddress, messageFacade, tradeId, depositTransaction);
state = State.SendDepositTxIdToTaker;
}
public void onResultSendDepositTxIdToTaker()
{
log.debug("onResultSendDepositTxIdToTaker called ");
SetupListenerForBlockChainConfirmation.run(this::onResultSetupListenerForBlockChainConfirmation, this::onFault, trade.getDepositTransaction(), listener);
state = State.SetupListenerForBlockChainConfirmation;
}
public void onResultSetupListenerForBlockChainConfirmation()
{
log.debug("onResultSetupListenerForBlockChainConfirmation called ");
state = State.onResultSetupListenerForBlockChainConfirmation;
listener.onWaitingForUserInteraction(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered from UI event: Button click "Bank transfer inited"
public void onUIEventBankTransferInited()
{
log.debug("onUIEventBankTransferInited called ");
// validation
checkState(state == State.onResultSetupListenerForBlockChainConfirmation);
state = State.onUIEventBankTransferInited;
// next task
String depositTransactionId = trade.getDepositTransaction().getHashAsString();
SendSignedPayoutTx.run(this::onResultSendSignedPayoutTx,
this::onFault,
peerAddress,
messageFacade,
walletFacade,
tradeId,
peersPayoutAddress,
payoutAddress,
depositTransactionId,
collateral,
tradeAmount);
state = State.SendSignedPayoutTx;
}
public void onResultSendSignedPayoutTx()
{
log.debug("onResultSendSignedPayoutTx called ");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onPayoutTxPublishedMessage(PayoutTxPublishedMessage message)
{
log.debug("onPayoutTxPublishedMessage called ");
// validation
checkState(state == State.SendSignedPayoutTx);
checkArgument(tradeId.equals(message.getTradeId()));
String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex());
state = State.onPayoutTxPublishedMessage;
// next task
listener.onPayoutTxPublished(payoutTxAsHex);
listener.onCompleted(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
} }

View file

@ -3,7 +3,7 @@ package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.TransactionConfidence; import com.google.bitcoin.core.TransactionConfidence;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
public interface OffererAsBuyerProtocolListener public interface ProtocolForOffererAsBuyerListener
{ {
void onOfferAccepted(Offer offer); void onOfferAccepted(Offer offer);
@ -15,11 +15,11 @@ public interface OffererAsBuyerProtocolListener
void onPayoutTxPublished(String payoutTxID); void onPayoutTxPublished(String payoutTxID);
void onFault(Throwable throwable, OffererAsBuyerProtocol.State state); void onFault(Throwable throwable, ProtocolForOffererAsBuyer.State state);
void onWaitingForPeerResponse(OffererAsBuyerProtocol.State state); void onWaitingForPeerResponse(ProtocolForOffererAsBuyer.State state);
void onCompleted(OffererAsBuyerProtocol.State state); void onCompleted(ProtocolForOffererAsBuyer.State state);
void onWaitingForUserInteraction(OffererAsBuyerProtocol.State state); void onWaitingForUserInteraction(ProtocolForOffererAsBuyer.State state);
} }

View file

@ -1,11 +1,10 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.offerer.RequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -25,12 +24,7 @@ public class RequestTakerDepositPayment
String preparedOffererDepositTxAsHex, String preparedOffererDepositTxAsHex,
long offererTxOutIndex) long offererTxOutIndex)
{ {
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(tradeId, RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(tradeId, bankAccount, accountId, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
bankAccount,
accountId,
offererPubKey,
preparedOffererDepositTxAsHex,
offererTxOutIndex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener() messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{ {
@Override @Override

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.offerer; package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
@ -9,7 +9,6 @@ public class RequestTakerDepositPaymentMessage implements Serializable, TradeMes
private static final long serialVersionUID = -3988720410493712913L; private static final long serialVersionUID = -3988720410493712913L;
private final String tradeId; private final String tradeId;
private BankAccount bankAccount; private BankAccount bankAccount;
private String accountID; private String accountID;
private String offererPubKey; private String offererPubKey;
@ -37,7 +36,7 @@ public class RequestTakerDepositPaymentMessage implements Serializable, TradeMes
return bankAccount; return bankAccount;
} }
public String getAccountID() public String getAccountId()
{ {
return accountID; return accountID;
} }

View file

@ -0,0 +1,28 @@
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
public class RespondToTakeOfferRequestMessage implements Serializable, TradeMessage
{
private static final long serialVersionUID = 6177387534087739018L;
private final String tradeId;
private boolean takeOfferRequestAccepted;
public RespondToTakeOfferRequestMessage(String tradeId, boolean takeOfferRequestAccepted)
{
this.tradeId = tradeId;
this.takeOfferRequestAccepted = takeOfferRequestAccepted;
}
@Override
public String getTradeId()
{
return tradeId;
}
public boolean isTakeOfferRequestAccepted()
{
return takeOfferRequestAccepted;
}
}

View file

@ -1,12 +1,11 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.Transaction; import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils; import com.google.bitcoin.core.Utils;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View file

@ -1,12 +1,11 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.ECKey; import com.google.bitcoin.core.ECKey;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import java.math.BigInteger; import java.math.BigInteger;
import javafx.util.Pair; import javafx.util.Pair;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
@ -34,11 +33,7 @@ public class SendSignedPayoutTx
BigInteger offererPaybackAmount = tradeAmount.add(collateral); BigInteger offererPaybackAmount = tradeAmount.add(collateral);
BigInteger takerPaybackAmount = collateral; BigInteger takerPaybackAmount = collateral;
Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransactionId, Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransactionId, offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, tradeId);
offererPaybackAmount,
takerPaybackAmount,
takerPayoutAddress,
tradeId);
ECKey.ECDSASignature offererSignature = result.getKey(); ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString(); String offererSignatureR = offererSignature.r.toString();

View file

@ -0,0 +1,38 @@
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SetupListenerForBlockChainConfirmation
{
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, Transaction depositTransaction, ProtocolForOffererAsBuyerListener listener)
{ //TODO
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().addEventListener(new TransactionConfidence.Listener()
{
@Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason)
{
log.trace("onConfidenceChanged " + tx.getConfidence());
if (reason == ChangeReason.SEEN_PEERS)
{
listener.onDepositTxConfirmedUpdate(tx.getConfidence());
}
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
listener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().removeEventListener(this);
log.trace("Tx is in blockchain");
resultHandler.onResult();
}
}
});
}
}

View file

@ -0,0 +1,60 @@
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishDepositTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
String preparedOffererDepositTxAsHex,
String signedTakerDepositTxAsHex,
String txConnOutAsHex,
String txScriptSigAsHex,
long offererTxOutIndex,
long takerTxOutIndex)
{
try
{
walletFacade.offererSignAndPublishTx(preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex,
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.trace("offererSignAndPublishTx succeeded " + transaction);
resultHandler.onResult(transaction);
}
@Override
public void onFailure(Throwable t)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(Transaction depositTransaction);
}
}

View file

@ -1,11 +1,11 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.ECKey; import com.google.bitcoin.core.ECKey;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.trade.Contract; import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import java.math.BigInteger; import java.math.BigInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -30,15 +30,7 @@ public class VerifyAndSignContract
String peersContractAsJson, String peersContractAsJson,
ECKey registrationKey) ECKey registrationKey)
{ {
Contract contract = new Contract(offer, Contract contract = new Contract(offer, tradeAmount, takeOfferFeeTxId, accountId, peersAccountId, bankAccount, peersBankAccount, messagePubKeyAsHex, takerMessagePubKey);
tradeAmount,
takeOfferFeeTxId,
accountId,
peersAccountId,
bankAccount,
peersBankAccount,
messagePubKeyAsHex,
takerMessagePubKey);
String contractAsJson = Utilities.objectToJson(contract); String contractAsJson = Utilities.objectToJson(contract);
// log.trace("Offerer contract created: " + contract); // log.trace("Offerer contract created: " + contract);

View file

@ -1,8 +1,8 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler; import io.bitsquare.trade.protocol.ResultHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View file

@ -0,0 +1,20 @@
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.shared.VerifyPeerAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyTakerAccount
{
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{
VerifyPeerAccount.run(resultHandler, faultHandler, blockChainFacade, peersAccountId, peersBankAccount);
}
}

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock; package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl. //TODO not used but let it for reference until all use cases are impl.
class BuyOffererPaymentProcess extends PaymentProcess class BuyOffererPaymentProcess extends PaymentProcess

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock; package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl. //TODO not used but let it for reference until all use cases are impl.
public class BuyTakerPaymentProcess extends PaymentProcess public class BuyTakerPaymentProcess extends PaymentProcess

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock; package io.bitsquare.trade.protocol.old;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.BlockChainFacade;

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock; package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl. //TODO not used but let it for reference until all use cases are impl.
class SellOffererPaymentProcess extends PaymentProcess class SellOffererPaymentProcess extends PaymentProcess

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock; package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl. //TODO not used but let it for reference until all use cases are impl.
class SellTakerPaymentProcess extends PaymentProcess class SellTakerPaymentProcess extends PaymentProcess

View file

@ -1,15 +1,15 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.shared;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler; import io.bitsquare.trade.protocol.ResultHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class VerifyTakerAccount public class VerifyPeerAccount
{ {
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class); private static final Logger log = LoggerFactory.getLogger(VerifyPeerAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount) public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{ {

View file

@ -0,0 +1,51 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.ECKey;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.util.Utilities;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateAndSignContract
{
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
CryptoFacade cryptoFacade,
Offer offer,
BigInteger tradeAmount,
String takeOfferFeeTxId,
String accountId,
BankAccount bankAccount,
String peersMessagePubKeyAsHex,
String messagePubKeyAsHex,
String peersAccountId,
BankAccount peersBankAccount,
ECKey registrationKey)
{
try
{
Contract contract = new Contract(offer, tradeAmount, takeOfferFeeTxId, peersAccountId, accountId, peersBankAccount, bankAccount, peersMessagePubKeyAsHex, messagePubKeyAsHex);
String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
resultHandler.onResult(contract, contractAsJson, signature);
} catch (Throwable t)
{
log.error("Exception at sign contract " + t);
faultHandler.onFault(t);
}
}
public interface ResultHandler
{
void onResult(Contract contract, String contractAsJson, String signature);
}
}

View file

@ -1,8 +1,8 @@
package io.bitsquare.trade.protocol.tasks.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.GetPeerAddressListener; import io.bitsquare.msg.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.FaultHandler;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View file

@ -0,0 +1,54 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayDeposit
{
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
BigInteger collateral,
BigInteger tradeAmount,
String tradeId,
String pubKeyForThatTrade,
String arbitratorPubKey,
String offererPubKey,
String preparedOffererDepositTxAsHex)
{
try
{
BigInteger amountToPay = tradeAmount.add(collateral);
BigInteger msOutputAmount = amountToPay.add(collateral);
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(amountToPay,
msOutputAmount,
offererPubKey,
pubKeyForThatTrade,
arbitratorPubKey,
preparedOffererDepositTxAsHex,
tradeId);
log.trace("sharedModel.signedTakerDepositTx: " + signedTakerDepositTx);
resultHandler.onResult(signedTakerDepositTx);
} catch (InsufficientMoneyException e)
{
log.error("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e);
faultHandler.onFault(new Exception("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e));
}
}
public interface ResultHandler
{
void onResult(Transaction signedTakerDepositTx);
}
}

View file

@ -1,10 +1,10 @@
package io.bitsquare.trade.protocol.tasks.taker; package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.InsufficientMoneyException; import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction; import com.google.bitcoin.core.Transaction;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.FaultHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -23,7 +23,7 @@ public class PayTakeOfferFee
public void onSuccess(Transaction transaction) public void onSuccess(Transaction transaction)
{ {
log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString()); log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString());
resultHandler.onResult(transaction); resultHandler.onResult(transaction.getHashAsString());
} }
@Override @Override
@ -42,7 +42,7 @@ public class PayTakeOfferFee
public interface ResultHandler public interface ResultHandler
{ {
void onResult(Transaction transaction); void onResult(String takeOfferFeeTxId);
} }
} }

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
import java.io.Serializable; import java.io.Serializable;

View file

@ -0,0 +1,400 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.offerer.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.offerer.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.offerer.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.offerer.RespondToTakeOfferRequestMessage;
import io.bitsquare.user.User;
import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer.
* That class handles the role of the taker as the Bitcoin seller.
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
*/
public class ProtocolForTakerAsSeller
{
private static final Logger log = LoggerFactory.getLogger(ProtocolForTakerAsSeller.class);
public enum State
{
Init,
GetPeerAddress,
RequestTakeOffer,
PayTakeOfferFee,
onRequestTakerDepositPaymentMessage,
SendTakeOfferFeePayedTxId,
VerifyOffererAccount,
CreateAndSignContract,
PayDeposit,
SendSignedTakerDepositTxAsHex,
onDepositTxPublishedMessage,
onBankTransferInitedMessage,
onUIEventFiatReceived,
SignAndPublishPayoutTx,
SendPayoutTxToOfferer
}
// provided data
private final Trade trade;
private final ProtocolForTakerAsSellerListener listener;
private final MessageFacade messageFacade;
private final WalletFacade walletFacade;
private final BlockChainFacade blockChainFacade;
private final CryptoFacade cryptoFacade;
// derived
private final String id;
private final Offer offer;
private final String tradeId;
private final BankAccount bankAccount;
private final String accountId;
private final String messagePubKey;
private final BigInteger tradeAmount;
private final String pubKeyForThatTrade;
private final ECKey accountKey;
private final String peersMessagePubKey;
private final BigInteger collateral;
private final String arbitratorPubKey;
// written/read by task
private PeerAddress peerAddress;
// written by messages, read by tasks
private String peersAccountId;
private BankAccount peersBankAccount;
private String peersPubKey;
private String preparedPeersDepositTxAsHex;
private long peersTxOutIndex;
private String depositTxAsHex;
private String offererSignatureR;
private String offererSignatureS;
private BigInteger offererPaybackAmount;
private BigInteger takerPaybackAmount;
private String offererPayoutAddress;
// state
private State state;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ProtocolForTakerAsSeller(Trade trade,
ProtocolForTakerAsSellerListener listener,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user)
{
this.trade = trade;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
offer = trade.getOffer();
tradeId = trade.getId();
tradeAmount = trade.getTradeAmount();
collateral = trade.getCollateralAmount();
arbitratorPubKey = trade.getOffer().getArbitrator().getPubKeyAsHex();
pubKeyForThatTrade = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
bankAccount = user.getBankAccount(offer.getBankAccountId());
accountId = user.getAccountId();
messagePubKey = user.getMessagePubKeyAsHex();
peersMessagePubKey = offer.getMessagePubKeyAsHex();
accountKey = walletFacade.getRegistrationAddressInfo().getKey();
id = trade.getId();
state = State.Init;
}
public void start()
{
log.debug("start called");
GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, messageFacade, peersMessagePubKey);
state = State.GetPeerAddress;
}
public void onResultGetPeerAddress(PeerAddress peerAddress)
{
log.debug(" called");
this.peerAddress = peerAddress;
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, peerAddress, messageFacade, tradeId);
state = State.RequestTakeOffer;
}
public void onResultRequestTakeOffer()
{
log.debug(" called");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message)
{
log.debug("onRespondToTakeOfferRequestMessage called");
checkState(state == State.RequestTakeOffer);
checkArgument(tradeId.equals(message.getTradeId()));
if (message.isTakeOfferRequestAccepted())
{
PayTakeOfferFee.run(this::onResultPayTakeOfferFee, this::onFault, walletFacade, tradeId);
state = State.PayTakeOfferFee;
}
else
{
listener.onTakeOfferRequestRejected(trade);
}
}
public void onResultPayTakeOfferFee(String takeOfferFeeTxId)
{
log.debug("onResultPayTakeOfferFee called");
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
SendTakeOfferFeePayedTxId.run(this::onResultSendTakeOfferFeePayedTxId, this::onFault, peerAddress, messageFacade, tradeId, takeOfferFeeTxId, tradeAmount, pubKeyForThatTrade);
state = State.SendTakeOfferFeePayedTxId;
}
public void onResultSendTakeOfferFeePayedTxId()
{
log.debug("onResultSendTakeOfferFeePayedTxId called");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage message)
{
log.debug("onRequestTakerDepositPaymentMessage called");
// validation
checkState(state == State.SendTakeOfferFeePayedTxId);
checkArgument(tradeId.equals(message.getTradeId()));
String peersAccountId = nonEmptyStringOf(message.getAccountId());
BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
String offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
String preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
// apply new state
state = State.onRequestTakerDepositPaymentMessage;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.peersPubKey = offererPubKey;
this.preparedPeersDepositTxAsHex = preparedOffererDepositTxAsHex;
this.peersTxOutIndex = offererTxOutIndex;
// next task
VerifyOffererAccount.run(this::onResultVerifyOffererAccount, this::onFault, blockChainFacade, peersAccountId, peersBankAccount);
state = State.VerifyOffererAccount;
}
public void onResultVerifyOffererAccount()
{
log.debug("onResultVerifyOffererAccount called");
String takeOfferFeeTxId = trade.getTakeOfferFeeTxId();
CreateAndSignContract.run(this::onResultCreateAndSignContract,
this::onFault,
cryptoFacade,
offer,
tradeAmount,
takeOfferFeeTxId,
accountId,
bankAccount,
peersMessagePubKey,
messagePubKey,
peersAccountId,
peersBankAccount,
accountKey);
state = State.CreateAndSignContract;
}
public void onResultCreateAndSignContract(Contract contract, String contractAsJson, String signature)
{
log.debug("onResultCreateAndSignContract called");
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
PayDeposit.run(this::onResultPayDeposit, this::onFault, walletFacade, collateral, tradeAmount, tradeId, pubKeyForThatTrade, arbitratorPubKey, peersPubKey, preparedPeersDepositTxAsHex);
state = State.PayDeposit;
}
public void onResultPayDeposit(Transaction signedTakerDepositTx)
{
log.debug("onResultPayDeposit called");
String contractAsJson = trade.getContractAsJson();
String takerSignature = trade.getTakerSignature();
SendSignedTakerDepositTxAsHex.run(this::onResultSendSignedTakerDepositTxAsHex,
this::onFault,
peerAddress,
messageFacade,
walletFacade,
bankAccount,
accountId,
messagePubKey,
tradeId,
contractAsJson,
takerSignature,
signedTakerDepositTx,
peersTxOutIndex);
state = State.SendSignedTakerDepositTxAsHex;
}
public void onResultSendSignedTakerDepositTxAsHex()
{
log.debug(" called");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// informational, does only trigger UI feedback/update
public void onDepositTxPublishedMessage(DepositTxPublishedMessage message)
{
log.debug("onDepositTxPublishedMessage called");
checkState(state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
checkArgument(tradeId.equals(message.getTradeId()));
state = State.onDepositTxPublishedMessage;
listener.onDepositTxPublished(walletFacade.takerCommitDepositTx(message.getDepositTxAsHex()));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// informational, store data for later, does only trigger UI feedback/update
public void onBankTransferInitedMessage(BankTransferInitedMessage message)
{
log.debug("onBankTransferInitedMessage called");
// validate
checkState(state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
checkArgument(tradeId.equals(message.getTradeId()));
String depositTxAsHex = nonEmptyStringOf(message.getDepositTxAsHex());
String offererSignatureR = nonEmptyStringOf(message.getOffererSignatureR());
String offererSignatureS = nonEmptyStringOf(message.getOffererSignatureS());
BigInteger offererPaybackAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getOffererPaybackAmount()));
BigInteger takerPaybackAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getTakerPaybackAmount()));
String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress());
// apply state
state = State.onBankTransferInitedMessage;
this.depositTxAsHex = depositTxAsHex;
this.offererSignatureR = offererSignatureR;
this.offererSignatureS = offererSignatureS;
this.offererPaybackAmount = offererPaybackAmount;
this.takerPaybackAmount = takerPaybackAmount;
this.offererPayoutAddress = offererPayoutAddress;
listener.onBankTransferInited(message.getTradeId());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event
///////////////////////////////////////////////////////////////////////////////////////////
// User clicked the "bank transfer received" button, so we release the funds for pay out
public void onUIEventFiatReceived()
{
log.debug("onUIEventFiatReceived called");
checkState(state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
state = State.onUIEventFiatReceived;
SignAndPublishPayoutTx.run(this::onResultSignAndPublishPayoutTx,
this::onFault,
walletFacade,
tradeId,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
state = State.SignAndPublishPayoutTx;
}
public void onResultSignAndPublishPayoutTx(String transactionId, String payoutTxAsHex)
{
log.debug("onResultSignAndPublishPayoutTx called");
listener.onPayoutTxPublished(trade, transactionId);
SendPayoutTxToOfferer.run(this::onResultSendPayoutTxToOfferer, this::onFault, peerAddress, messageFacade, tradeId, payoutTxAsHex);
state = State.SendPayoutTxToOfferer;
}
public void onResultSendPayoutTxToOfferer()
{
log.debug("onResultSendPayoutTxToOfferer called");
listener.onCompleted(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
}

View file

@ -2,7 +2,7 @@ package io.bitsquare.trade.protocol.taker;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
public interface TakerAsSellerProtocolListener public interface ProtocolForTakerAsSellerListener
{ {
void onDepositTxPublished(String depositTxId); void onDepositTxPublished(String depositTxId);
@ -10,11 +10,11 @@ public interface TakerAsSellerProtocolListener
void onPayoutTxPublished(Trade trade, String hashAsString); void onPayoutTxPublished(Trade trade, String hashAsString);
void onFault(Throwable throwable, TakerAsSellerProtocol.State state); void onFault(Throwable throwable, ProtocolForTakerAsSeller.State state);
void onWaitingForPeerResponse(TakerAsSellerProtocol.State state); void onWaitingForPeerResponse(ProtocolForTakerAsSeller.State state);
void onCompleted(TakerAsSellerProtocol.State state); void onCompleted(ProtocolForTakerAsSeller.State state);
void onTakeOfferRequestRejected(Trade trade); void onTakeOfferRequestRejected(Trade trade);
} }

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
@ -62,12 +62,12 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return offererTxOutIndex; return offererTxOutIndex;
} }
public BankAccount getBankAccount() public BankAccount getTakerBankAccount()
{ {
return bankAccount; return bankAccount;
} }
public String getAccountId() public String getTakerAccountId()
{ {
return accountID; return accountID;
} }
@ -92,7 +92,7 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return txConnOutAsHex; return txConnOutAsHex;
} }
public String getContractAsJson() public String getTakerContractAsJson()
{ {
return contractAsJson; return contractAsJson;
} }

View file

@ -1,10 +1,9 @@
package io.bitsquare.trade.protocol.tasks.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.taker.RequestTakeOfferMessage; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
import java.io.Serializable; import java.io.Serializable;

View file

@ -1,11 +1,9 @@
package io.bitsquare.trade.protocol.tasks.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -14,9 +12,9 @@ public class SendPayoutTxToOfferer
{ {
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class); private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade trade, String payoutTxAsHex) public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, String tradeId, String payoutTxAsHex)
{ {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(trade.getId(), payoutTxAsHex); PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener() messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{ {
@Override @Override

View file

@ -0,0 +1,67 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendSignedTakerDepositTxAsHex
{
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
BankAccount bankAccount,
String accountId,
String messagePubKeyAsHex,
String tradeId,
String contractAsJson,
String takerSignature,
Transaction signedTakerDepositTx,
long offererTxOutIndex)
{
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(tradeId,
bankAccount,
accountId,
messagePubKeyAsHex,
Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1)
.getConnectedOutput()
.getParentTransaction()
.bitcoinSerialize()),
contractAsJson,
takerSignature,
walletFacade.getAddressInfoByTradeID(tradeId).getAddressString(),
takerTxOutIndex,
offererTxOutIndex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
resultHandler.onResult();
}
@Override
public void onFailed()
{
log.error("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer"));
}
});
}
}

View file

@ -1,10 +1,9 @@
package io.bitsquare.trade.protocol.tasks.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage; import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import java.math.BigInteger; import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -21,12 +20,9 @@ public class SendTakeOfferFeePayedTxId
String tradeId, String tradeId,
String takeOfferFeeTxId, String takeOfferFeeTxId,
BigInteger tradeAmount, BigInteger tradeAmount,
String pubKeyAsHexString) String pubKeyForThatTradeAsHex)
{ {
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId, TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId, takeOfferFeeTxId, tradeAmount, pubKeyForThatTradeAsHex);
takeOfferFeeTxId,
tradeAmount,
pubKeyAsHexString);
messageFacade.sendTradeMessage(peerAddress, msg, new OutgoingTradeMessageListener() messageFacade.sendTradeMessage(peerAddress, msg, new OutgoingTradeMessageListener()
{ {

View file

@ -0,0 +1,66 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishPayoutTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
String tradeId,
String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererPayoutAddress)
{
try
{
walletFacade.takerSignsAndSendsTx(depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
tradeId,
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.debug("takerSignsAndSendsTx " + transaction);
String payoutTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
resultHandler.onResult(transaction.getHashAsString(), payoutTxAsHex);
}
@Override
public void onFailure(Throwable t)
{
log.error("Exception at takerSignsAndSendsTx " + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("Exception at takerSignsAndSendsTx " + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(String transactionId, String payoutTxAsHex);
}
}

View file

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker; package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
import java.io.Serializable; import java.io.Serializable;
@ -11,14 +11,14 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage
private BigInteger tradeAmount; private BigInteger tradeAmount;
private String takeOfferFeeTxID; private String takeOfferFeeTxID;
private String takerMultiSigPubKey; private String takerPubKey;
public TakeOfferFeePayedMessage(String tradeId, String takeOfferFeeTxID, BigInteger tradeAmount, String takerMultiSigPubKey) public TakeOfferFeePayedMessage(String tradeId, String takeOfferFeeTxID, BigInteger tradeAmount, String takerPubKey)
{ {
this.tradeId = tradeId; this.tradeId = tradeId;
this.takeOfferFeeTxID = takeOfferFeeTxID; this.takeOfferFeeTxID = takeOfferFeeTxID;
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
this.takerMultiSigPubKey = takerMultiSigPubKey; this.takerPubKey = takerPubKey;
} }
@Override @Override
@ -37,9 +37,9 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage
return takeOfferFeeTxID; return takeOfferFeeTxID;
} }
public String getTakerMultiSigPubKey() public String getTakerPubKey()
{ {
return takerMultiSigPubKey; return takerPubKey;
} }
} }

View file

@ -1,882 +0,0 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.messages.offerer.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.tasks.taker.*;
import io.bitsquare.user.User;
import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
import static io.bitsquare.util.Validator.nonNegativeLongOf;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer.
* That class handles the role of the taker as the Bitcoin seller.
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
*/
public class TakerAsSellerProtocol
{
private static final Logger log = LoggerFactory.getLogger(TakerAsSellerProtocol.class);
// provided data
private final Trade trade;
private final TakerAsSellerProtocolListener listener;
private final MessageFacade messageFacade;
private final WalletFacade walletFacade;
private final BlockChainFacade blockChainFacade;
private final CryptoFacade cryptoFacade;
private final User user;
private final String id;
private final Offer offer;
private final String tradeId;
// written/read by task
private String payoutTxAsHex;
private PeerAddress peerAddress;
private Transaction signedTakerDepositTx;
private long takerTxOutIndex;
// written by message, read by tasks
private String peersAccountId;
private BankAccount peersBankAccount;
private String offererPubKey;
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
private String depositTxAsHex;
private String offererSignatureR;
private String offererSignatureS;
private BigInteger offererPaybackAmount;
private BigInteger takerPaybackAmount;
private String offererPayoutAddress;
//private
private State state;
public TakerAsSellerProtocol(Trade trade,
TakerAsSellerProtocolListener listener,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user)
{
this.trade = trade;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
this.user = user;
offer = trade.getOffer();
tradeId = trade.getId();
id = trade.getId();
state = State.Init;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
public void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
public void start()
{
String messagePubKeyAsHex = nonEmptyStringOf(offer.getMessagePubKeyAsHex());
GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, messageFacade, messagePubKeyAsHex);
state = State.GetPeerAddress;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultGetPeerAddress(PeerAddress peerAddress)
{
this.peerAddress = checkNotNull(peerAddress);
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, this.peerAddress, messageFacade, tradeId);
state = State.RequestTakeOffer;
}
public void onResultRequestTakeOffer()
{
listener.onWaitingForPeerResponse(state);
}
public void onAcceptTakeOfferRequestMessage()
{
log.debug("onAcceptTakeOfferRequestMessage");
checkState(state == State.RequestTakeOffer);
PayTakeOfferFee.run(this::onResultPayTakeOfferFee, this::onFault, walletFacade, tradeId);
state = State.PayTakeOfferFee;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// OR
public void onRejectTakeOfferRequestMessage()
{
log.debug("onRejectTakeOfferRequestMessage");
checkState(state == State.RequestTakeOffer);
state = State.onRejectTakeOfferRequestMessage;
listener.onTakeOfferRequestRejected(trade);
}
public void onResultPayTakeOfferFee(Transaction transaction)
{
checkNotNull(transaction);
String transactionId = nonEmptyStringOf(transaction.getHashAsString());
trade.setTakeOfferFeeTxID(transactionId);
String takeOfferFeeTxId = trade.getTakeOfferFeeTxId();
BigInteger tradeAmount = trade.getTradeAmount();
String pubKeyAsHexString = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
SendTakeOfferFeePayedTxId.run(this::onResultSendTakeOfferFeePayedTxId,
this::onFault,
peerAddress,
messageFacade,
tradeId,
takeOfferFeeTxId,
tradeAmount,
pubKeyAsHexString);
state = State.SendTakeOfferFeePayedTxId;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultSendTakeOfferFeePayedTxId()
{
listener.onWaitingForPeerResponse(state);
}
public void onRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage message)
{
log.debug("onRequestTakerDepositPaymentMessage");
checkState(state == State.SendTakeOfferFeePayedTxId);
peersAccountId = nonEmptyStringOf(message.getAccountID());
peersBankAccount = checkNotNull(message.getBankAccount());
offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
VerifyOffererAccount.run(this::onResultVerifyOffererAccount,
this::onFault,
blockChainFacade,
peersAccountId,
peersBankAccount);
state = State.VerifyOffererAccount;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultVerifyOffererAccount()
{
CreateAndSignContract.run(this::onResultCreateAndSignContract,
this::onFault,
cryptoFacade,
trade,
user,
peersAccountId,
peersBankAccount,
walletFacade.getRegistrationAddressInfo().getKey());
state = State.CreateAndSignContract;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultCreateAndSignContract()
{
PayDeposit.run(this::onResultPayDeposit, this::onFault, walletFacade, trade, offererPubKey, preparedOffererDepositTxAsHex);
state = State.PayDeposit;
}
public void onResultPayDeposit(Transaction signedTakerDepositTx, long takerTxOutIndex)
{
SendSignedTakerDepositTxAsHex.run(this::onResultSendSignedTakerDepositTxAsHex,
this::onFault,
peerAddress,
messageFacade,
walletFacade,
trade,
user,
signedTakerDepositTx,
takerTxOutIndex,
offererTxOutIndex);
state = State.SendSignedTakerDepositTxAsHex;
}
public void onResultSendSignedTakerDepositTxAsHex()
{
listener.onWaitingForPeerResponse(state);
}
// informational, does only trigger UI feedback/update
public void onDepositTxPublishedMessage(DepositTxPublishedMessage message)
{
log.debug("onDepositTxPublishedMessage");
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
{
state = State.onDepositTxPublishedMessage;
listener.onDepositTxPublished(walletFacade.takerCommitDepositTx(message.getDepositTxAsHex()));
}
else
{
log.error("Invalid state. Actual state is: " + state);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// informational, store data for later, does only trigger UI feedback/update
public void onBankTransferInitedMessage(BankTransferInitedMessage tradeMessage)
{
log.debug("onBankTransferInitedMessage");
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
{
state = State.onBankTransferInitedMessage;
depositTxAsHex = tradeMessage.getDepositTxAsHex();
offererSignatureR = tradeMessage.getOffererSignatureR();
offererSignatureS = tradeMessage.getOffererSignatureS();
offererPaybackAmount = tradeMessage.getOffererPaybackAmount();
takerPaybackAmount = tradeMessage.getTakerPaybackAmount();
offererPayoutAddress = tradeMessage.getOffererPayoutAddress();
listener.onBankTransferInited(tradeMessage.getTradeId());
}
else
{
log.error("Invalid state. Actual state is: " + state);
}
}
// User clicked the "bank transfer received" button, so we release the funds for pay out
public void onUIEventFiatReceived()
{
log.debug("onUIEventFiatReceived");
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
{
state = State.onUIEventFiatReceived;
SignAndPublishPayoutTx.run(this::onResultSignAndPublishPayoutTx,
this::onFault,
walletFacade,
trade,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
state = State.SignAndPublishPayoutTx;
}
else
{
log.error("Invalid state. Actual state is: " + state);
}
}
public void onResultSignAndPublishPayoutTx(Transaction transaction, String payoutTxAsHex)
{
listener.onPayoutTxPublished(trade, transaction.getHashAsString());
SendPayoutTxToOfferer.run(this::onResultSendPayoutTxToOfferer, this::onFault, peerAddress, messageFacade, trade, payoutTxAsHex);
state = State.SendPayoutTxToOfferer;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultSendPayoutTxToOfferer()
{
checkState(state == State.SendPayoutTxToOfferer);
listener.onCompleted(state);
}
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public enum State
{
Init,
GetPeerAddress,
RequestTakeOffer,
PayTakeOfferFee,
onRejectTakeOfferRequestMessage,
SendTakeOfferFeePayedTxId,
VerifyOffererAccount,
CreateAndSignContract,
PayDeposit,
SendSignedTakerDepositTxAsHex,
onDepositTxPublishedMessage,
onBankTransferInitedMessage,
onUIEventFiatReceived,
SignAndPublishPayoutTx,
SendPayoutTxToOfferer
}
///////////////////////////////////////////////////////////////////////////////////////////
// Step 1.1
///////////////////////////////////////////////////////////////////////////////////////////
/* private void findPeerAddress()
{
log.debug("1.1 findPeerAddress");
AddressLookupListener addressLookupListener = new AddressLookupListener()
{
@Override
public void onResult(PeerAddress address)
{
log.debug("1.1 findPeerAddress onResult");
// We got the peer address
peerAddress = address;
takerPaymentProtocolListener.onProgress(getProgress());
// next
requestTakeOffer();
}
@Override
public void onFailed()
{
log.debug("1.1 findPeerAddress onFailed");
takerPaymentProtocolListener.onFailure("onGetPeerAddressFailed");
}
};
takerPaymentProtocolListener.onProgress(getProgress());
// Request the peers address from the DHT
messageFacade.getPeerAddress(offer.getMessagePubKeyAsHex(), addressLookupListener);
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 1.2
///////////////////////////////////////////////////////////////////////////////////////////
/* private void requestTakeOffer()
{
log.debug("1.2 requestTakeOffer");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("1.2 requestTakeOffer onResult");
// Our message has arrived
// We don't know yet if the offerer has accepted
// the take request (if offer is not already reserved for another user)
// We await for an incoming message from the offerer with the accept msg
takerPaymentProtocolListener.onProgress(getProgress());
// Wait for message from offerer...
}
@Override
public void onFailed()
{
log.debug("1.2 requestTakeOffer onFailed");
takerPaymentProtocolListener.onFailure("sendTakeOfferRequest onSendTradingMessageFailed");
}
};
takerPaymentProtocolListener.onProgress(getProgress());
// Send the take offer request
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_TAKE_OFFER, trade.getId());
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
} */
//************************************************************************************************
// 1.3. Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 1.4
///////////////////////////////////////////////////////////////////////////////////////////
// 1.4a offerer has accepted the take offer request. Move on to step 2.
/* public void onAcceptTakeOfferRequestMessage()
{
log.debug("1.4a onAcceptTakeOfferRequestMessage");
// listener.onProgress(getProgress());
payOfferFee(trade);
}
// 1.4b Offerer has rejected the take offer request. The UI controller will onResult the case.
public void onRejectTakeOfferRequestMessage()
{
log.debug("1.4b onRejectTakeOfferRequestMessage");
// listener.onProgress(getProgress());
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.1
///////////////////////////////////////////////////////////////////////////////////////////
/* private void payOfferFee(Trade trade)
{
log.debug("2.1 payTakeOfferFee");
FutureCallback<Transaction> callback = new FutureCallback<Transaction>()
{
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{
log.debug("2.1 payTakeOfferFee onSuccess");
log.info("sendResult onSuccess txid:" + transaction.getHashAsString());
// Offer fee payed successfully.
trade.setTakeOfferFeeTxID(transaction.getHashAsString());
// listener.onProgress(getProgress());
// move on
sendTakerOfferFeeTxID(transaction.getHashAsString());
}
@Override
public void onFailure(Throwable t)
{
log.debug("2.1 payTakeOfferFee onFailure");
// listener.onFailure("payTakeOfferFee onFailure " + t.getMessage());
}
};
try
{
// Pay the offer fee
// listener.onProgress(getProgress());
walletFacade.payTakeOfferFee(trade.getId(), callback);
} catch (InsufficientMoneyException e)
{
// listener.onProgress(getProgress());
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.2
///////////////////////////////////////////////////////////////////////////////////////////
// Request peers account details. At that moment private data (bank account nr.) of the offerer get visible to the taker.
// We send also the tx id of the fee payment, so the offerer can confirm that the payment is seen in the network
// 0 block confirmation is acceptable for the fee to not block the process
// The offerer will wait until a minimum of peers seen the tx before sending his data.
// We also get the multisig tx delivered
/* private void sendTakerOfferFeeTxID(String takeOfferFeeTxID)
{
log.debug("2.2 sendTakerOfferFeeTxID");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("2.2 sendTakerOfferFeeTxID onResult");
// Message has arrived
//listener.onProgress(getProgress());
// We wait until the offerer send us the data
}
@Override
public void onFailed()
{
log.debug("2.2 sendTakerOfferFeeTxID onFailed");
// //TakerAsSellerProtocol.this. listener.onFailure("requestAccountDetails onSendTradingMessageFailed");
}
};
// this.listener.onProgress(getProgress());
// 2.3. send request for the account details and send fee tx id so offerer can verify that the fee has been paid.
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.TAKE_OFFER_FEE_PAYED,
trade.getId(),
trade.getTradeAmount(),
takeOfferFeeTxID,
walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString());
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
}
*/
//************************************************************************************************
// 2.3 - 2.6 Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.7 Incoming msg from offerer
///////////////////////////////////////////////////////////////////////////////////////////
/*public void onRequestTakerDepositPaymentMessage(TradeMessageOld requestTradeMessage)
{
log.debug("2.7 onRequestTakerDepositPaymentMessage");
verifyOfferer(requestTradeMessage);
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.8 Verify offerers account registration and against the blacklist
///////////////////////////////////////////////////////////////////////////////////////////
/*private void verifyOfferer(TradeMessageOld requestTradeMessage)
{
log.debug("2.8 verifyOfferer");
log.debug("2.8.1 verifyAccountRegistration");
if (blockChainFacade.verifyAccountRegistration())
{
log.debug("2.8.2 isAccountBlackListed");
if (blockChainFacade.isAccountBlackListed(requestTradeMessage.getAccountId(), requestTradeMessage.getBankAccount()))
{
// listener.onFailure("Offerer is blacklisted.");
}
else
{
createAndSignContract(requestTradeMessage);
}
}
else
{
// listener.onFailure("Offerers account registration is invalid.");
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.9 Create and sign the contract
///////////////////////////////////////////////////////////////////////////////////////////
/* private void createAndSignContract(TradeMessageOld requestTradeMessage)
{
log.debug("2.9 createAndSignContract");
checkNotNull(trade.getOffer());
checkNotNull(trade.getTradeAmount());
checkNotNull(trade.getTakeOfferFeeTxId());
checkNotNull(requestTradeMessage.getAccountId());
checkNotNull(user.getAccountId());
checkNotNull(requestTradeMessage.getBankAccount());
checkNotNull(user.getCurrentBankAccount());
checkNotNull(user.getMessagePubKeyAsHex());
Contract contract = new Contract(trade.getOffer(),
trade.getTradeAmount(),
trade.getTakeOfferFeeTxId(),
requestTradeMessage.getAccountId(),
user.getAccountId(),
requestTradeMessage.getBankAccount(),
user.getCurrentBankAccount(),
trade.getOffer().getMessagePubKeyAsHex(),
user.getMessagePubKeyAsHex()
);
log.debug("2.9 contract created: " + contract);
String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(walletFacade.getRegistrationAddressInfo().getKey(), contractAsJson);
//log.debug("2.9 contractAsJson: " + contractAsJson);
log.debug("2.9 contract signature: " + signature);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
payDeposit(requestTradeMessage);
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.10 Pay in the funds to the deposit tx and sign it
///////////////////////////////////////////////////////////////////////////////////////////
/*private void payDeposit(TradeMessageOld requestTradeMessage)
{
log.debug("2.10 payDeposit");
BigInteger collateralAmount = trade.getCollateralAmount();
BigInteger takerInputAmount = trade.getTradeAmount().add(collateralAmount);
BigInteger msOutputAmount = trade.getTradeAmount().add(collateralAmount).add(collateralAmount);
String offererPubKey = requestTradeMessage.getOffererPubKey();
String takerPubKey = walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
String arbitratorPubKey = trade.getOffer().getArbitrator().getPubKeyAsHex();
String preparedOffererDepositTxAsHex = requestTradeMessage.getPreparedOffererDepositTxAsHex();
checkNotNull(takerInputAmount);
checkNotNull(msOutputAmount);
checkNotNull(offererPubKey);
checkNotNull(takerPubKey);
checkNotNull(arbitratorPubKey);
checkNotNull(preparedOffererDepositTxAsHex);
log.debug("2.10 offererCreatesMSTxAndAddPayment");
log.debug("takerAmount " + BtcFormatter.formatSatoshis(takerInputAmount));
log.debug("msOutputAmount " + BtcFormatter.formatSatoshis(msOutputAmount));
log.debug("offerer pubkey " + offererPubKey);
log.debug("taker pubkey " + takerPubKey);
log.debug("arbitrator pubkey " + arbitratorPubKey);
log.debug("preparedOffererDepositTxAsHex " + preparedOffererDepositTxAsHex);
try
{
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(takerInputAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, preparedOffererDepositTxAsHex, trade.getId());
log.debug("2.10 deposit tx created: " + signedTakerDepositTx);
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
sendSignedTakerDepositTxAsHex(signedTakerDepositTx, takerTxOutIndex, requestTradeMessage.getOffererTxOutIndex());
} catch (InsufficientMoneyException e)
{
log.error("2.10 error at walletFacade.takerAddPaymentAndSign: " + e.getMessage());
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.11 Send the tx to the offerer
///////////////////////////////////////////////////////////////////////////////////////////
/* private void sendSignedTakerDepositTxAsHex(Transaction signedTakerDepositTx, long takerTxOutIndex, long offererTxOutIndex)
{
log.debug("2.11 sendSignedTakerDepositTxAsHex");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("2.11 sendSignedTakerDepositTxAsHex REQUEST_TAKER_DEPOSIT_PAYMENT onResult");
// Message arrived at taker
// //TakerAsSellerProtocol.this. listener.onFailure(getProgress());
}
@Override
public void onFailed()
{
log.debug("2.11 sendSignedTakerDepositTxAsHex REQUEST_TAKER_DEPOSIT_PAYMENT onFailed");
////TakerAsSellerProtocol.this. listener.onFailure("sendSignedTakerDepositTxAsHex REQUEST_TAKER_DEPOSIT_PAYMENT onFailed");
}
};
// this.listener.onProgress(getProgress());
BankAccount bankAccount = user.getCurrentBankAccount();
String accountID = user.getAccountId();
String messagePubKey = user.getMessagePubKeyAsHex();
String contractAsJson = trade.getContractAsJson();
String signature = trade.getTakerSignature();
String signedTakerDepositTxAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize());
String txScriptSigAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes());
String txConnOutAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize());
//TODO just 1 address supported yet
String payoutAddress = walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString();
log.debug("2.10 deposit txAsHex: " + signedTakerDepositTxAsHex);
log.debug("2.10 txScriptSigAsHex: " + txScriptSigAsHex);
log.debug("2.10 txConnOutAsHex: " + txConnOutAsHex);
log.debug("2.10 payoutAddress: " + payoutAddress);
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.REQUEST_OFFERER_DEPOSIT_PUBLICATION,
trade.getId(),
bankAccount,
accountID,
messagePubKey,
signedTakerDepositTxAsHex,
txScriptSigAsHex,
txConnOutAsHex,
contractAsJson,
signature,
payoutAddress,
takerTxOutIndex,
offererTxOutIndex
);
log.debug("2.11 sendTradingMessage");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
} */
//************************************************************************************************
// 3.1 - 3.5 Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.6 Incoming msg from offerer
///////////////////////////////////////////////////////////////////////////////////////////
/* public void onDepositTxPublishedMessage(TradeMessageOld tradeMessage)
{
log.debug("3.6 DepositTxID received: " + tradeMessage.getDepositTxAsHex());
String txID = walletFacade.takerCommitDepositTx(tradeMessage.getDepositTxAsHex());
// listener.onProgress(getProgress());
listener.onDepositTxPublishedMessage(txID);
} */
//************************************************************************************************
// 3.7-3.10 Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.11 Incoming msg from offerer
///////////////////////////////////////////////////////////////////////////////////////////
/* public void onBankTransferInitedMessage(BankTransferInitedMessage tradeMessage)
{
log.debug("3.11 Bank transfer inited msg received");
listener.onBankTransferInitedMessage(tradeMessage);
} */
//************************************************************************************************
// Taker will check periodically his bank account until he received the money. That might take a while...
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.12 User clicked the "bank transfer received" button, so we release the funds for pay out
///////////////////////////////////////////////////////////////////////////////////////////
/* public void onUIEventFiatReceived(TradeMessageOld tradeMessage)
{
log.debug("3.12 onUIEventFiatReceived");
FutureCallback<Transaction> callback = new FutureCallback<Transaction>()
{
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{
System.out.println("######### 3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
log.debug("3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
listener.onPayoutTxPublished(transaction.getHashAsString());
sendPayoutTxToOfferer(Utils.bytesToHexString(transaction.bitcoinSerialize()));
}
@Override
public void onFailure(Throwable t)
{
log.error("######### 3.12 onFailure walletFacade.takerSignsAndSendsTx");
System.err.println("3.12 onFailure walletFacade.takerSignsAndSendsTx");
// listener.onFailure("takerSignsAndSendsTx failed " + t.getMessage());
}
};
try
{
String depositTxAsHex = tradeMessage.getDepositTxAsHex();
String offererSignatureR = tradeMessage.getOffererSignatureR();
String offererSignatureS = tradeMessage.getOffererSignatureS();
BigInteger offererPaybackAmount = tradeMessage.getOffererPaybackAmount();
BigInteger takerPaybackAmount = tradeMessage.getTakerPaybackAmount();
String offererPayoutAddress = tradeMessage.getOffererPayoutAddress();
log.debug("3.12 walletFacade.takerSignsAndSendsTx");
walletFacade.takerSignsAndSendsTx(depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
trade.getId(),
callback);
} catch (AddressFormatException e)
{
log.error("3.12 offererCreatesAndSignsPayoutTx onFailed AddressFormatException " + e.getMessage());
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.13 Send payout txID to offerer
///////////////////////////////////////////////////////////////////////////////////////////
/*void sendPayoutTxToOfferer(String payoutTxAsHex)
{
log.debug("3.13 sendPayoutTxToOfferer ");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("3.13 sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onResult");
log.debug("3.13 TRADE COMPLETE!!!!!!!!!!!");
//TakerAsSellerProtocol.this. listener.onFailure(getProgress());
}
@Override
public void onFailed()
{
log.debug("3.13 sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onFailed");
//TakerAsSellerProtocol.this. listener.onFailure("sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onFailed");
}
};
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.PAYOUT_TX_PUBLISHED, trade.getId());
tradeMessage.setPayoutTxAsHex(payoutTxAsHex);
log.debug("3.13 sendTradeMessage PAYOUT_TX_PUBLISHED");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
} */
/* private double getProgress()
{
currentStep++;
int numberOfSteps = 10;
return (double) currentStep / (double) numberOfSteps;
} */
}

View file

@ -0,0 +1,19 @@
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.shared.VerifyPeerAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyOffererAccount
{
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{
VerifyPeerAccount.run(resultHandler, faultHandler, blockChainFacade, peersAccountId, peersBankAccount);
}
}

View file

@ -1,65 +0,0 @@
package io.bitsquare.trade.protocol.tasks.offerer;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.offerer.AcceptTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.messages.offerer.RejectTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HandleTakeOfferRequest
{
private static final Logger log = LoggerFactory.getLogger(HandleTakeOfferRequest.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade.State tradeState, String tradeId)
{
if (tradeState == Trade.State.OPEN)
{
messageFacade.sendTradeMessage(peerAddress, new AcceptTakeOfferRequestMessage(tradeId), new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("AcceptTakeOfferRequestMessage successfully arrived at peer");
resultHandler.onResult(Trade.State.ACCEPTED);
}
@Override
public void onFailed()
{
log.error("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer"));
}
});
}
else
{
RejectTakeOfferRequestMessage msg = new RejectTakeOfferRequestMessage(tradeId);
messageFacade.sendTradeMessage(peerAddress, msg, new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RejectTakeOfferRequestMessage successfully arrived at peer");
}
@Override
public void onFailed()
{
log.error("RejectTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
}
});
log.error("Offer not marked as open.");
faultHandler.onFault(new Exception("Offer not marked as open."));
}
}
public interface ResultHandler
{
void onResult(Trade.State tradeState);
}
}

View file

@ -1,40 +0,0 @@
package io.bitsquare.trade.protocol.tasks.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence;
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocolListener;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SetupListenerForBlockChainConfirmation
{
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, Transaction depositTransaction, OffererAsBuyerProtocolListener listener)
{ //TODO
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().addEventListener(new TransactionConfidence.Listener()
{
@Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason)
{
log.trace("onConfidenceChanged " + tx.getConfidence());
if (reason == ChangeReason.SEEN_PEERS)
{
listener.onDepositTxConfirmedUpdate(tx.getConfidence());
}
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
listener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().removeEventListener(this);
log.trace("Tx is in blockchain");
resultHandler.onResult();
}
}
}
);
}
}

View file

@ -1,60 +0,0 @@
package io.bitsquare.trade.protocol.tasks.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishDepositTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
String preparedOffererDepositTxAsHex,
String signedTakerDepositTxAsHex,
String txConnOutAsHex,
String txScriptSigAsHex,
long offererTxOutIndex,
long takerTxOutIndex)
{
try
{
walletFacade.offererSignAndPublishTx(preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex,
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.trace("offererSignAndPublishTx succeeded " + transaction);
resultHandler.onResult(transaction);
}
@Override
public void onFailure(Throwable t)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(Transaction transaction);
}
}

View file

@ -1,60 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.ECKey;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.user.User;
import io.bitsquare.util.Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateAndSignContract
{
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
CryptoFacade cryptoFacade,
Trade trade,
User user,
String peersAccountId,
BankAccount peersBankAccount,
ECKey registrationKey)
{
try
{
Contract contract = new Contract(trade.getOffer(),
trade.getTradeAmount(),
trade.getTakeOfferFeeTxId(),
peersAccountId,
user.getAccountId(),
peersBankAccount,
user.getCurrentBankAccount(),
trade.getOffer().getMessagePubKeyAsHex(),
user.getMessagePubKeyAsHex()
);
String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
//log.trace("contract: " + contract);
//log.debug("contractAsJson: " + contractAsJson);
//log.trace("contract signature: " + signature);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
resultHandler.onResult();
} catch (Throwable t)
{
log.error("Exception at sign contract " + t);
faultHandler.onFault(t);
}
}
}

View file

@ -1,46 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayDeposit
{
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, WalletFacade walletFacade, Trade trade, String offererPubKey, String preparedOffererDepositTxAsHex)
{
try
{
BigInteger collateralAmount = trade.getCollateralAmount();
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(trade.getTradeAmount().add(collateralAmount),
trade.getTradeAmount().add(collateralAmount).add(collateralAmount),
offererPubKey,
walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString(),
trade.getOffer().getArbitrator().getPubKeyAsHex(),
preparedOffererDepositTxAsHex,
trade.getId());
log.trace("sharedModel.signedTakerDepositTx: " + signedTakerDepositTx);
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
resultHandler.onResult(signedTakerDepositTx, takerTxOutIndex);
} catch (InsufficientMoneyException e)
{
log.error("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e);
faultHandler.onFault(new Exception("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e));
}
}
public interface ResultHandler
{
void onResult(Transaction signedTakerDepositTx, long takerTxOutIndex);
}
}

View file

@ -1,61 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.user.User;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendSignedTakerDepositTxAsHex
{
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
Trade trade,
User user,
Transaction signedTakerDepositTx,
long takerTxOutIndex,
long offererTxOutIndex)
{
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(trade.getId(),
user.getCurrentBankAccount(),
user.getAccountId(),
user.getMessagePubKeyAsHex(),
Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize()),
trade.getContractAsJson(),
trade.getTakerSignature(),
walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString(),
takerTxOutIndex,
offererTxOutIndex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
resultHandler.onResult();
}
@Override
public void onFailed()
{
log.error("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer"));
}
});
}
}

View file

@ -1,68 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishPayoutTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
Trade trade,
String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererPayoutAddress
)
{
try
{
walletFacade.takerSignsAndSendsTx(depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
trade.getId(),
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.debug("takerSignsAndSendsTx " + transaction);
String payoutTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
resultHandler.onResult(transaction, payoutTxAsHex);
}
@Override
public void onFailure(Throwable t)
{
log.error("Exception at takerSignsAndSendsTx " + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("Exception at takerSignsAndSendsTx " + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(Transaction transaction, String payoutTxAsHex);
}
}

View file

@ -1,35 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyOffererAccount
{
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{
//TODO mocked yet
if (blockChainFacade.verifyAccountRegistration())
{
if (blockChainFacade.isAccountBlackListed(peersAccountId, peersBankAccount))
{
log.error("Offerer is blacklisted");
faultHandler.onFault(new Exception("Offerer is blacklisted"));
}
else
{
resultHandler.onResult();
}
}
else
{
log.error("Account Registration for peer faultHandler.onFault.");
faultHandler.onFault(new Exception("Account Registration for peer faultHandler.onFault."));
}
}
}

View file

@ -94,18 +94,26 @@ public class Arbitrator implements Serializable
public int hashCode() public int hashCode()
{ {
if (id != null) if (id != null)
{
return Objects.hashCode(id); return Objects.hashCode(id);
}
else else
{
return 0; return 0;
} }
}
@SuppressWarnings("NonFinalFieldReferenceInEquals") @SuppressWarnings("NonFinalFieldReferenceInEquals")
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if (!(obj instanceof Arbitrator)) if (!(obj instanceof Arbitrator))
{
return false; return false;
}
if (obj == this) if (obj == this)
{
return true; return true;
}
Arbitrator other = (Arbitrator) obj; Arbitrator other = (Arbitrator) obj;
return id != null && id.equals(other.getId()); return id != null && id.equals(other.getId());

View file

@ -46,17 +46,28 @@ public class User implements Serializable
public void addBankAccount(BankAccount bankAccount) public void addBankAccount(BankAccount bankAccount)
{ {
if (!bankAccounts.contains(bankAccount)) if (!bankAccounts.contains(bankAccount))
{
bankAccounts.add(bankAccount); bankAccounts.add(bankAccount);
}
currentBankAccount = bankAccount; currentBankAccount = bankAccount;
} }
public void removeCurrentBankAccount() public void removeCurrentBankAccount()
{ {
if (currentBankAccount != null) bankAccounts.remove(currentBankAccount); if (currentBankAccount != null)
{
bankAccounts.remove(currentBankAccount);
}
if (bankAccounts.isEmpty()) currentBankAccount = null; if (bankAccounts.isEmpty())
else currentBankAccount = bankAccounts.get(0); {
currentBankAccount = null;
}
else
{
currentBankAccount = bankAccounts.get(0);
}
} }
@ -74,7 +85,9 @@ public class User implements Serializable
bankAccountUIDs += bankAccount.toString(); bankAccountUIDs += bankAccount.toString();
if (i < bankAccounts.size() - 1) if (i < bankAccounts.size() - 1)
{
bankAccountUIDs += ", "; bankAccountUIDs += ", ";
}
} }
return bankAccountUIDs; return bankAccountUIDs;
@ -136,8 +149,10 @@ public class User implements Serializable
for (final BankAccount bankAccount : bankAccounts) for (final BankAccount bankAccount : bankAccounts)
{ {
if (bankAccount.getUid().equals(bankAccountId)) if (bankAccount.getUid().equals(bankAccountId))
{
return bankAccount; return bankAccount;
} }
}
return null; return null;
} }

View file

@ -60,9 +60,13 @@ public class DSAKeyUtil
} catch (Throwable throwable) } catch (Throwable throwable)
{ {
if (throwable instanceof FileNotFoundException) if (throwable instanceof FileNotFoundException)
{
log.debug("Files not found. That is ok for the first execute."); log.debug("Files not found. That is ok for the first execute.");
}
else else
{
log.error("Could not read key files. " + throwable); log.error("Could not read key files. " + throwable);
}
try try
{ {
@ -114,16 +118,24 @@ public class DSAKeyUtil
// Work around an issue on Windows whereby you can't rename over existing files. // Work around an issue on Windows whereby you can't rename over existing files.
final File pubKeyCanonicalFile = pubKeyFile.getCanonicalFile(); final File pubKeyCanonicalFile = pubKeyFile.getCanonicalFile();
if (pubKeyCanonicalFile.exists() && !pubKeyCanonicalFile.delete()) if (pubKeyCanonicalFile.exists() && !pubKeyCanonicalFile.delete())
{
throw new IOException("Failed to delete pubKeyCanonicalFile for replacement with save"); throw new IOException("Failed to delete pubKeyCanonicalFile for replacement with save");
}
if (!pubKeyTempFile.renameTo(pubKeyCanonicalFile)) if (!pubKeyTempFile.renameTo(pubKeyCanonicalFile))
{
throw new IOException("Failed to rename " + pubKeyTempFile + " to " + pubKeyCanonicalFile); throw new IOException("Failed to rename " + pubKeyTempFile + " to " + pubKeyCanonicalFile);
}
final File privKeyCanonicalFile = privKeyFile.getCanonicalFile(); final File privKeyCanonicalFile = privKeyFile.getCanonicalFile();
if (privKeyCanonicalFile.exists() && !privKeyCanonicalFile.delete()) if (privKeyCanonicalFile.exists() && !privKeyCanonicalFile.delete())
{
throw new IOException("Failed to delete privKeyCanonicalFile for replacement with save"); throw new IOException("Failed to delete privKeyCanonicalFile for replacement with save");
}
if (!privKeyTempFile.renameTo(privKeyCanonicalFile)) if (!privKeyTempFile.renameTo(privKeyCanonicalFile))
{
throw new IOException("Failed to rename " + privKeyTempFile + " to " + privKeyCanonicalFile); throw new IOException("Failed to rename " + privKeyTempFile + " to " + privKeyCanonicalFile);
} }
}
else else
{ {
if (!pubKeyTempFile.renameTo(pubKeyFile)) if (!pubKeyTempFile.renameTo(pubKeyFile))
@ -141,14 +153,18 @@ public class DSAKeyUtil
{ {
log.warn("PubKeyTempFile still exists after failed save."); log.warn("PubKeyTempFile still exists after failed save.");
if (!pubKeyTempFile.delete()) if (!pubKeyTempFile.delete())
{
log.warn("Cannot delete pubKeyTempFile."); log.warn("Cannot delete pubKeyTempFile.");
} }
}
if (privKeyTempFile.exists()) if (privKeyTempFile.exists())
{ {
log.warn("PrivKeyTempFile still exists after failed save."); log.warn("PrivKeyTempFile still exists after failed save.");
if (!privKeyTempFile.delete()) if (!privKeyTempFile.delete())
{
log.warn("Cannot delete privKeyTempFile."); log.warn("Cannot delete privKeyTempFile.");
} }
}
lock.unlock(); lock.unlock();
} }

View file

@ -33,8 +33,10 @@ public class FileUtil
if (!dir.exists()) if (!dir.exists())
{ {
if (!dir.mkdir()) if (!dir.mkdir())
{
log.error("Could not create directory. " + dir.getAbsolutePath()); log.error("Could not create directory. " + dir.getAbsolutePath());
} }
}
return dir; return dir;
} }

View file

@ -82,7 +82,9 @@ public class Utilities
private static void printElapsedTime(String msg) private static void printElapsedTime(String msg)
{ {
if (!msg.isEmpty()) if (!msg.isEmpty())
{
msg += " / "; msg += " / ";
}
long timeStamp = System.currentTimeMillis(); long timeStamp = System.currentTimeMillis();
log.debug(msg + "Elapsed: " + String.valueOf(timeStamp - lastTimeStamp)); log.debug(msg + "Elapsed: " + String.valueOf(timeStamp - lastTimeStamp));
lastTimeStamp = timeStamp; lastTimeStamp = timeStamp;