Merge pull request #1490 from ManfredKarrer/voting

Improve data structure, refactor Proposal domain
This commit is contained in:
Manfred Karrer 2018-04-01 19:27:23 -05:00 committed by GitHub
commit 86ad6ef41a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 273 additions and 323 deletions

View file

@ -48,8 +48,8 @@ import bisq.core.btc.wallet.WalletService;
import bisq.core.btc.wallet.WalletsManager;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.DaoManager;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.vote.VoteService;
import bisq.core.dao.vote.blindvote.BlindVoteService;
import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.filter.FilterManager;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
@ -229,8 +229,8 @@ public class BisqApp extends Application {
persistedDataHosts.add(injector.getInstance(FailedTradesManager.class));
persistedDataHosts.add(injector.getInstance(DisputeManager.class));
persistedDataHosts.add(injector.getInstance(P2PService.class));
persistedDataHosts.add(injector.getInstance(ProposalCollectionsService.class));
persistedDataHosts.add(injector.getInstance(VoteService.class));
persistedDataHosts.add(injector.getInstance(ProposalService.class));
persistedDataHosts.add(injector.getInstance(BlindVoteService.class));
// we apply at startup the reading of persisted data but don't want to get it triggered in the constructor
persistedDataHosts.forEach(e -> {

View file

@ -17,7 +17,7 @@
package bisq.desktop.components;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.locale.Res;
import bisq.common.UserThread;

View file

@ -26,13 +26,13 @@ import bisq.desktop.components.TableGroupHeadline;
import bisq.desktop.util.BsqFormatter;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import bisq.core.dao.node.BsqNode;
import bisq.core.dao.proposal.Proposal;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.proposal.ProposalPayload;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.dao.vote.proposal.Proposal;
import bisq.core.dao.vote.proposal.ProposalPayload;
import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.locale.Res;
import javax.inject.Inject;
@ -67,12 +67,11 @@ import java.util.List;
import java.util.stream.Collectors;
@FxmlView
public abstract class BaseProposalView extends ActivatableView<GridPane, Void> implements BsqNode.BsqBlockChainListener {
public abstract class BaseProposalView extends ActivatableView<GridPane, Void> implements BsqBlockChain.Listener {
protected final ProposalCollectionsService proposalCollectionsService;
protected final BsqBlockChain bsqBlockChain;
protected final ProposalService proposalService;
protected final ReadableBsqBlockChain readableBsqBlockChain;
protected final BsqWalletService bsqWalletService;
protected final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
protected final BsqFormatter bsqFormatter;
protected final ObservableList<ProposalListItem> proposalListItems = FXCollections.observableArrayList();
@ -97,16 +96,14 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
protected BaseProposalView(ProposalCollectionsService proposalCollectionsService,
protected BaseProposalView(ProposalService proposalService,
BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
ReadableBsqBlockChain readableBsqBlockChain,
DaoPeriodService daoPeriodService,
BsqFormatter bsqFormatter) {
this.proposalCollectionsService = proposalCollectionsService;
this.proposalService = proposalService;
this.bsqWalletService = bsqWalletService;
this.bsqBlockChain = bsqBlockChain;
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
this.readableBsqBlockChain = readableBsqBlockChain;
this.daoPeriodService = daoPeriodService;
this.bsqFormatter = bsqFormatter;
}
@ -128,8 +125,8 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
selectedProposalSubscription = EasyBind.subscribe(proposalTableView.getSelectionModel().selectedItemProperty(), this::onSelectProposal);
daoPeriodService.getPhaseProperty().addListener(phaseChangeListener);
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
proposalCollectionsService.getAllProposals().addListener(proposalListChangeListener);
readableBsqBlockChain.addListener(this);
proposalService.getAllProposals().addListener(proposalListChangeListener);
onPhaseChanged(daoPeriodService.getPhaseProperty().get());
@ -144,8 +141,8 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
selectedProposalSubscription.unsubscribe();
daoPeriodService.getPhaseProperty().removeListener(phaseChangeListener);
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
proposalCollectionsService.getAllProposals().removeListener(proposalListChangeListener);
readableBsqBlockChain.removeListener(this);
proposalService.getAllProposals().removeListener(proposalListChangeListener);
sortedList.comparatorProperty().unbind();
@ -156,11 +153,11 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
///////////////////////////////////////////////////////////////////////////////////////////
// API
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onBsqBlockChainChanged() {
public void onBlockAdded(BsqBlock bsqBlock) {
// Need delay otherwise we modify list while dispatching and cause a ConcurrentModificationException
//UserThread.execute(this::updateList);
}
@ -256,11 +253,10 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
proposalListItems.setAll(list.stream()
.map(proposal -> new ProposalListItem(proposal,
proposalCollectionsService,
proposalService,
daoPeriodService,
bsqWalletService,
bsqBlockChain,
bsqBlockChainChangeDispatcher,
readableBsqBlockChain,
bsqFormatter))
.collect(Collectors.toSet()));
@ -391,7 +387,7 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
};
}
});
uidColumn.setComparator(Comparator.comparing(o -> o.getProposal().getProposalPayload().getUid()));
uidColumn.setComparator(Comparator.comparing(o -> o.getProposal().getUid()));
tableView.getColumns().add(uidColumn);
}

View file

@ -22,7 +22,7 @@ import bisq.desktop.util.BsqFormatter;
import bisq.desktop.util.Layout;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.proposal.ProposalPayload;
import bisq.core.dao.vote.proposal.ProposalPayload;
import bisq.core.locale.Res;
import javafx.geometry.Insets;

View file

@ -28,11 +28,11 @@ import bisq.desktop.util.validation.BsqAddressValidator;
import bisq.desktop.util.validation.BsqValidator;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.proposal.ProposalPayload;
import bisq.core.dao.proposal.ProposalType;
import bisq.core.dao.proposal.compensation.CompensationRequestPayload;
import bisq.core.dao.proposal.compensation.consensus.Restrictions;
import bisq.core.dao.proposal.consensus.ProposalConsensus;
import bisq.core.dao.vote.proposal.ProposalConsensus;
import bisq.core.dao.vote.proposal.ProposalPayload;
import bisq.core.dao.vote.proposal.ProposalType;
import bisq.core.dao.vote.proposal.compensation.CompensationRequestConsensus;
import bisq.core.dao.vote.proposal.compensation.CompensationRequestPayload;
import bisq.core.locale.Res;
import bisq.core.provider.fee.FeeService;
@ -136,7 +136,7 @@ public class ProposalDisplay {
BsqValidator bsqValidator = new BsqValidator(bsqFormatter);
//TODO should we use the BSQ or a BTC validator? Technically it is BTC at that stage...
//bsqValidator.setMinValue(feeService.getCreateCompensationRequestFee());
bsqValidator.setMinValue(Restrictions.getMinCompensationRequestAmount());
bsqValidator.setMinValue(CompensationRequestConsensus.getMinCompensationRequestAmount());
Objects.requireNonNull(requestedBsqTextField).setValidator(bsqValidator);
}
// TODO validator, addressTF

View file

@ -23,15 +23,15 @@ import bisq.desktop.util.BsqFormatter;
import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.dao.blockchain.vo.Tx;
import bisq.core.dao.node.BsqNode;
import bisq.core.dao.proposal.Proposal;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.vote.BooleanVoteResult;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.dao.vote.VoteResult;
import bisq.core.dao.vote.proposal.Proposal;
import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.locale.Res;
import org.bitcoinj.core.Transaction;
@ -54,14 +54,13 @@ import lombok.extern.slf4j.Slf4j;
@ToString
@Slf4j
@EqualsAndHashCode
public class ProposalListItem implements BsqNode.BsqBlockChainListener {
public class ProposalListItem implements BsqBlockChain.Listener {
@Getter
private final Proposal proposal;
private final ProposalCollectionsService proposalCollectionsService;
private final ProposalService proposalService;
private final DaoPeriodService daoPeriodService;
private final BsqWalletService bsqWalletService;
private final ReadableBsqBlockChain readableBsqBlockChain;
private final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
private final BsqFormatter bsqFormatter;
private final ChangeListener<Number> chainHeightListener;
private final ChangeListener<VoteResult> voteResultChangeListener;
@ -81,18 +80,16 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
private Node actionNode;
ProposalListItem(Proposal proposal,
ProposalCollectionsService proposalCollectionsService,
ProposalService proposalService,
DaoPeriodService daoPeriodService,
BsqWalletService bsqWalletService,
ReadableBsqBlockChain readableBsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
BsqFormatter bsqFormatter) {
this.proposal = proposal;
this.proposalCollectionsService = proposalCollectionsService;
this.proposalService = proposalService;
this.daoPeriodService = daoPeriodService;
this.bsqWalletService = bsqWalletService;
this.readableBsqBlockChain = readableBsqBlockChain;
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
this.bsqFormatter = bsqFormatter;
@ -111,7 +108,7 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
setupConfidence();
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
readableBsqBlockChain.addListener(this);
phaseChangeListener = (observable, oldValue, newValue) -> {
applyState(newValue, proposal.getVoteResult());
@ -134,7 +131,7 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
case UNDEFINED:
break;
case PROPOSAL:
if (proposalCollectionsService.isMine(proposal)) {
if (proposalService.isMine(proposal)) {
actionButton.setVisible(!isTxInPastCycle);
actionButtonIconView.setVisible(actionButton.isVisible());
actionButton.setText(Res.get("shared.remove"));
@ -188,11 +185,18 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
//actionButtonIconView.setManaged(actionButtonIconView.isVisible());
}
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onBsqBlockChainChanged() {
public void onBlockAdded(BsqBlock bsqBlock) {
//TODO do we want that here???
setupConfidence();
}
private void setupConfidence() {
final Tx tx = readableBsqBlockChain.getTxMap().get(proposal.getProposalPayload().getTxId());
if (tx != null) {
@ -238,7 +242,7 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
}
public void cleanup() {
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
readableBsqBlockChain.removeListener(this);
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
if (txConfidenceListener != null)
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);

View file

@ -30,15 +30,13 @@ import bisq.core.btc.exceptions.TransactionVerificationException;
import bisq.core.btc.exceptions.WalletException;
import bisq.core.btc.wallet.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.ChangeBelowDustException;
import bisq.core.btc.wallet.InsufficientBsqException;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import bisq.core.dao.proposal.Proposal;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.vote.BooleanVoteResult;
import bisq.core.dao.vote.VoteService;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.dao.vote.blindvote.BlindVoteService;
import bisq.core.dao.vote.proposal.Proposal;
import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.locale.Res;
import bisq.common.crypto.CryptoException;
@ -66,6 +64,8 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.util.Callback;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@ -82,7 +82,7 @@ import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
@FxmlView
public class ActiveProposalsView extends BaseProposalView implements BsqBalanceListener {
private final VoteService voteService;
private final BlindVoteService blindVoteService;
private Button removeButton, acceptButton, rejectButton, cancelVoteButton, voteButton;
private InputTextField stakeInputTextField;
@ -94,16 +94,15 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private ActiveProposalsView(ProposalCollectionsService voteRequestManger,
private ActiveProposalsView(ProposalService voteRequestManger,
DaoPeriodService daoPeriodService,
VoteService voteService,
BlindVoteService blindVoteService,
BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
ReadableBsqBlockChain readableBsqBlockChain,
BsqFormatter bsqFormatter) {
super(voteRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
super(voteRequestManger, bsqWalletService, readableBsqBlockChain, daoPeriodService,
bsqFormatter);
this.voteService = voteService;
this.blindVoteService = blindVoteService;
}
@Override
@ -133,7 +132,7 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
// TODO verify stake
//TODO show popup
try {
voteService.publishBlindVote(stake, new FutureCallback<Transaction>() {
blindVoteService.publishBlindVote(stake, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction result) {
//TODO
@ -155,10 +154,10 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
e1.printStackTrace();
} catch (InsufficientMoneyException e1) {
e1.printStackTrace();
} catch (ChangeBelowDustException e1) {
e1.printStackTrace();
} catch (InvalidProtocolBufferException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
});
}
@ -268,7 +267,7 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
final Proposal proposal = selectedProposalListItem.getProposal();
switch (phase) {
case PROPOSAL:
if (proposalCollectionsService.isMine(proposal)) {
if (proposalService.isMine(proposal)) {
if (removeButton == null) {
removeButton = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.active.remove"));
removeButton.setOnAction(event -> onRemove());
@ -327,12 +326,12 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
@Override
protected void updateProposalList() {
doUpdateProposalList(proposalCollectionsService.getActiveProposals());
doUpdateProposalList(proposalService.getActiveProposals());
}
private void updateStateAfterVote() {
hideProposalDisplay();
proposalCollectionsService.persist();
proposalService.persist();
proposalTableView.getSelectionModel().clearSelection();
}
@ -344,7 +343,7 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
}
private void onRemove() {
if (proposalCollectionsService.removeProposal(selectedProposalListItem.getProposal()))
if (proposalService.removeProposal(selectedProposalListItem.getProposal()))
hideProposalDisplay();
else
new Popup<>().warning(Res.get("dao.proposal.active.remove.failed")).show();

View file

@ -22,10 +22,9 @@ import bisq.desktop.main.dao.proposal.BaseProposalView;
import bisq.desktop.util.BsqFormatter;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.dao.vote.proposal.ProposalService;
import javax.inject.Inject;
@ -37,14 +36,12 @@ public class ClosedProposalsView extends BaseProposalView {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private ClosedProposalsView(ProposalCollectionsService proposalCollectionsService,
private ClosedProposalsView(ProposalService proposalService,
DaoPeriodService daoPeriodService,
BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
ReadableBsqBlockChain readableBsqBlockChain,
BsqFormatter bsqFormatter) {
super(proposalCollectionsService, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
bsqFormatter);
super(proposalService, bsqWalletService, readableBsqBlockChain, daoPeriodService, bsqFormatter);
}
@Override
@ -67,7 +64,7 @@ public class ClosedProposalsView extends BaseProposalView {
@Override
protected void updateProposalList() {
doUpdateProposalList(proposalCollectionsService.getClosedProposals());
doUpdateProposalList(proposalService.getClosedProposals());
}
}

View file

@ -23,7 +23,7 @@ import bisq.desktop.components.SeparatedPhaseBars;
import bisq.desktop.util.Layout;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.locale.Res;
import javax.inject.Inject;

View file

@ -29,19 +29,18 @@ import bisq.desktop.util.Layout;
import bisq.core.btc.exceptions.TransactionVerificationException;
import bisq.core.btc.exceptions.WalletException;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.ChangeBelowDustException;
import bisq.core.btc.wallet.InsufficientBsqException;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.proposal.Proposal;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.proposal.ProposalType;
import bisq.core.dao.proposal.compensation.CompensationAmountException;
import bisq.core.dao.proposal.compensation.CompensationRequestPayload;
import bisq.core.dao.proposal.compensation.CompensationRequestService;
import bisq.core.dao.proposal.consensus.ProposalConsensus;
import bisq.core.dao.proposal.generic.GenericProposalPayload;
import bisq.core.dao.proposal.generic.GenericProposalService;
import bisq.core.dao.vote.proposal.Proposal;
import bisq.core.dao.vote.proposal.ProposalConsensus;
import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.dao.vote.proposal.ProposalType;
import bisq.core.dao.vote.proposal.ValidationException;
import bisq.core.dao.vote.proposal.compensation.CompensationRequestPayload;
import bisq.core.dao.vote.proposal.compensation.CompensationRequestService;
import bisq.core.dao.vote.proposal.generic.GenericProposalPayload;
import bisq.core.dao.vote.proposal.generic.GenericProposalService;
import bisq.core.locale.Res;
import bisq.core.provider.fee.FeeService;
import bisq.core.util.CoinUtil;
@ -68,6 +67,8 @@ import javafx.collections.FXCollections;
import javafx.util.StringConverter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
@ -90,7 +91,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
private final WalletsSetup walletsSetup;
private final P2PService p2PService;
private final FeeService feeService;
private final ProposalCollectionsService proposalCollectionsService;
private final ProposalService proposalService;
private final CompensationRequestService compensationRequestService;
private final GenericProposalService genericProposalService;
private final ReadableBsqBlockChain readableBsqBlockChain;
@ -110,7 +111,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
WalletsSetup walletsSetup,
P2PService p2PService,
FeeService feeService,
ProposalCollectionsService proposalCollectionsService,
ProposalService proposalService,
CompensationRequestService compensationRequestService,
GenericProposalService genericProposalService,
ReadableBsqBlockChain readableBsqBlockChain,
@ -120,7 +121,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
this.walletsSetup = walletsSetup;
this.p2PService = p2PService;
this.feeService = feeService;
this.proposalCollectionsService = proposalCollectionsService;
this.proposalService = proposalService;
this.compensationRequestService = compensationRequestService;
this.genericProposalService = genericProposalService;
this.readableBsqBlockChain = readableBsqBlockChain;
@ -176,18 +177,16 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
Coin miningFee = Objects.requireNonNull(tx).getFee();
int txSize = tx.bitcoinSerialize().length;
validateInputs();
new Popup<>().headLine(Res.get("dao.proposal.create.confirm"))
.confirmation(Res.get("dao.proposal.create.confirm.info",
bsqFormatter.formatCoinWithCode(
ProposalConsensus.getCreateCompensationRequestFee(readableBsqBlockChain)),
bsqFormatter.formatCoinWithCode(ProposalConsensus.getFee(readableBsqBlockChain)),
btcFormatter.formatCoinWithCode(miningFee),
CoinUtil.getFeePerByte(miningFee, txSize),
(txSize / 1000d)))
txSize / 1000d))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> {
proposalCollectionsService.publishProposal(proposal, new FutureCallback<Transaction>() {
proposalService.publishProposal(proposal,
new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction transaction) {
proposalDisplay.clearForm();
@ -210,37 +209,45 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter;
new Popup<>().warning(Res.get("dao.proposal.create.missingFunds",
formatter.formatCoinWithCode(e.missing))).show();
} catch (CompensationAmountException e) {
new Popup<>().warning(Res.get("validation.bsq.amountBelowMinAmount",
bsqFormatter.formatCoinWithCode(e.required))).show();
} catch (TransactionVerificationException | WalletException e) {
} catch (ValidationException e) {
String message;
if (e.getMinRequestAmount() != null) {
message = Res.get("validation.bsq.amountBelowMinAmount",
bsqFormatter.formatCoinWithCode(e.getMinRequestAmount()));
} else {
message = e.getMessage();
}
new Popup<>().warning(message).show();
} catch (TransactionVerificationException | WalletException | IOException e) {
log.error(e.toString());
e.printStackTrace();
new Popup<>().warning(e.toString()).show();
} catch (ChangeBelowDustException e) {
//TODO
e.printStackTrace();
}
}
private Proposal createProposal(ProposalType type) throws InsufficientMoneyException, TransactionVerificationException, CompensationAmountException, WalletException, ChangeBelowDustException {
private Proposal createProposal(ProposalType type)
throws InsufficientMoneyException, TransactionVerificationException, ValidationException,
WalletException, IOException {
validateInputs();
switch (type) {
case COMPENSATION_REQUEST:
CompensationRequestPayload compensationRequestPayload = compensationRequestService.getNewCompensationRequestPayload(
CompensationRequestPayload compensationRequestPayload = compensationRequestService.getCompensationRequestPayload(
proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText(),
bsqFormatter.parseToCoin(Objects.requireNonNull(proposalDisplay.requestedBsqTextField).getText()),
Objects.requireNonNull(proposalDisplay.bsqAddressTextField).getText());
return compensationRequestService.prepareCompensationRequest(compensationRequestPayload);
return compensationRequestService.getCompensationRequest(compensationRequestPayload);
case GENERIC:
GenericProposalPayload genericProposalPayload = genericProposalService.getNewGenericProposalPayload(
GenericProposalPayload genericProposalPayload = genericProposalService.getGenericProposalPayload(
proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText());
return genericProposalService.prepareGenericProposal(genericProposalPayload);
return genericProposalService.getGenericProposal(genericProposalPayload);
case CHANGE_PARAM:
//TODO
return null;

View file

@ -29,16 +29,13 @@ import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.node.BsqNodeProvider;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.proposal.ProposalList;
import bisq.core.dao.vote.BooleanVoteResult;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.dao.vote.VoteResult;
import bisq.core.dao.vote.VoteService;
import bisq.core.dao.vote.blindvote.BlindVoteService;
import bisq.core.dao.vote.proposal.ProposalList;
import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.locale.Res;
import bisq.core.user.Preferences;
@ -74,10 +71,8 @@ import java.util.stream.Collectors;
@FxmlView
public class MyVotesView extends BaseProposalView {
private final VoteService voteService;
private final BlindVoteService blindVoteService;
private final ReadableBsqBlockChain readableBsqBlockChain;
private final BsqNodeProvider bsqNodeProvider;
private final Preferences preferences;
private final ObservableList<VoteListItem> voteListItems = FXCollections.observableArrayList();
@ -92,21 +87,17 @@ public class MyVotesView extends BaseProposalView {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private MyVotesView(ProposalCollectionsService voteRequestManger,
private MyVotesView(ProposalService voteRequestManger,
DaoPeriodService daoPeriodService,
VoteService voteService,
BlindVoteService blindVoteService,
BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
ReadableBsqBlockChain readableBsqBlockChain,
BsqNodeProvider bsqNodeProvider,
Preferences preferences,
BsqFormatter bsqFormatter) {
super(voteRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
super(voteRequestManger, bsqWalletService, readableBsqBlockChain, daoPeriodService,
bsqFormatter);
this.voteService = voteService;
this.blindVoteService = blindVoteService;
this.readableBsqBlockChain = readableBsqBlockChain;
this.bsqNodeProvider = bsqNodeProvider;
this.preferences = preferences;
}
@ -131,8 +122,8 @@ public class MyVotesView extends BaseProposalView {
sortedList.comparatorProperty().bind(votesTableView.comparatorProperty());
voteListItems.clear();
List<VoteListItem> items = voteService.getMyVotesList().stream()
.map(vote -> new VoteListItem(vote, bsqWalletService, readableBsqBlockChain, bsqNodeProvider, bsqFormatter))
List<VoteListItem> items = blindVoteService.getMyVotesList().stream()
.map(vote -> new VoteListItem(vote, bsqWalletService, readableBsqBlockChain, bsqFormatter))
.collect(Collectors.toList());
voteListItems.addAll(items);
}

View file

@ -22,11 +22,11 @@ import bisq.desktop.util.BsqFormatter;
import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.dao.blockchain.vo.Tx;
import bisq.core.dao.blockchain.vo.TxOutput;
import bisq.core.dao.node.BsqNode;
import bisq.core.dao.node.BsqNodeProvider;
import bisq.core.dao.vote.MyVote;
import bisq.core.locale.Res;
@ -51,7 +51,7 @@ import lombok.extern.slf4j.Slf4j;
@ToString
@Slf4j
@EqualsAndHashCode
public class VoteListItem implements BsqNode.BsqBlockChainListener {
public class VoteListItem implements BsqBlockChain.Listener {
@Getter
private final MyVote myVote;
private final BsqWalletService bsqWalletService;
@ -76,7 +76,6 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
VoteListItem(MyVote myVote,
BsqWalletService bsqWalletService,
ReadableBsqBlockChain readableBsqBlockChain,
BsqNodeProvider bsqNodeProvider,
BsqFormatter bsqFormatter) {
this.myVote = myVote;
this.bsqWalletService = bsqWalletService;
@ -89,7 +88,7 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
txConfidenceIndicator.setProgress(-1);
txConfidenceIndicator.setPrefSize(24, 24);
txConfidenceIndicator.setTooltip(tooltip);
bsqNodeProvider.getBsqNode().addBsqBlockChainListener(this);
readableBsqBlockChain.addListener(this);
chainHeightListener = (observable, oldValue, newValue) -> setupConfidence();
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
@ -97,12 +96,18 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
calculateStake();
}
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onBsqBlockChainChanged() {
public void onBlockAdded(BsqBlock bsqBlock) {
//TODO do we want that here???
setupConfidence();
calculateStake();
}
private void setupConfidence() {
calculateStake();
final Tx tx = readableBsqBlockChain.getTxMap().get(myVote.getBlindVote().getTxId());
@ -144,7 +149,7 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
private void calculateStake() {
if (stake == 0) {
String txId = myVote.getTxId();
stake = readableBsqBlockChain.getLockedForVoteTxOutputs().stream()
stake = readableBsqBlockChain.getBlindVoteStakeTxOutputs().stream()
.filter(txOutput -> txOutput.getTxId().equals(txId))
.filter(txOutput -> txOutput.getIndex() == 0)
.mapToLong(TxOutput::getValue)
@ -162,9 +167,9 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
public void cleanup() {
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
readableBsqBlockChain.removeListener(this);
if (txConfidenceListener != null)
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
}
private void updateConfidence(TransactionConfidence.ConfidenceType confidenceType, int depthInBlocks, int numBroadcastPeers) {

View file

@ -27,8 +27,8 @@ import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.node.BsqNode;
import bisq.core.dao.node.BsqNodeProvider;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.locale.Res;
import bisq.core.monetary.Altcoin;
import bisq.core.monetary.Price;
@ -57,11 +57,10 @@ import static bisq.desktop.util.FormBuilder.addLabelTextField;
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
@FxmlView
public class BsqDashboardView extends ActivatableView<GridPane, Void> implements BsqNode.BsqBlockChainListener {
public class BsqDashboardView extends ActivatableView<GridPane, Void> implements BsqBlockChain.Listener {
private final BsqBalanceUtil bsqBalanceUtil;
private final BsqNode bsqNode;
private final BsqBlockChain bsqBlockChain;
private final ReadableBsqBlockChain readableBsqBlockChain;
private final PriceFeedService priceFeedService;
private final Preferences preferences;
private final BsqFormatter bsqFormatter;
@ -80,14 +79,12 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
@Inject
private BsqDashboardView(BsqBalanceUtil bsqBalanceUtil,
BsqNodeProvider bsqNodeProvider,
BsqBlockChain bsqBlockChain,
ReadableBsqBlockChain readableBsqBlockChain,
PriceFeedService priceFeedService,
Preferences preferences,
BsqFormatter bsqFormatter) {
this.bsqBalanceUtil = bsqBalanceUtil;
this.bsqNode = bsqNodeProvider.getBsqNode();
this.bsqBlockChain = bsqBlockChain;
this.readableBsqBlockChain = readableBsqBlockChain;
this.priceFeedService = priceFeedService;
this.preferences = preferences;
this.bsqFormatter = bsqFormatter;
@ -100,13 +97,13 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
addTitledGroupBg(root, ++gridRow, 12, Res.get("dao.wallet.dashboard.statistics"), Layout.GROUP_DISTANCE);
addLabelTextField(root, gridRow, Res.get("dao.wallet.dashboard.genesisBlockHeight"),
String.valueOf(bsqBlockChain.getGenesisBlockHeight()), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
String.valueOf(readableBsqBlockChain.getGenesisBlockHeight()), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
Label label = new AutoTooltipLabel(Res.get("dao.wallet.dashboard.genesisTxId"));
GridPane.setRowIndex(label, ++gridRow);
root.getChildren().add(label);
hyperlinkWithIcon = new HyperlinkWithIcon(bsqBlockChain.getGenesisTxId(), AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", bsqBlockChain.getGenesisTxId())));
hyperlinkWithIcon = new HyperlinkWithIcon(readableBsqBlockChain.getGenesisTxId(), AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", readableBsqBlockChain.getGenesisTxId())));
GridPane.setRowIndex(hyperlinkWithIcon, gridRow);
GridPane.setColumnIndex(hyperlinkWithIcon, 1);
GridPane.setMargin(hyperlinkWithIcon, new Insets(0, 0, 0, -4));
@ -131,39 +128,48 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
protected void activate() {
bsqBalanceUtil.activate();
bsqNode.addBsqBlockChainListener(this);
readableBsqBlockChain.addListener(this);
priceFeedService.updateCounterProperty().addListener(priceChangeListener);
hyperlinkWithIcon.setOnAction(event -> GUIUtil.openWebPage(preferences.getBsqBlockChainExplorer().txUrl + bsqBlockChain.getGenesisTxId()));
hyperlinkWithIcon.setOnAction(event -> GUIUtil.openWebPage(preferences.getBsqBlockChainExplorer().txUrl + readableBsqBlockChain.getGenesisTxId()));
onBsqBlockChainChanged();
updateWithBsqBlockChainData();
updatePrice();
}
@Override
protected void deactivate() {
bsqBalanceUtil.deactivate();
bsqNode.removeBsqBlockChainListener(this);
readableBsqBlockChain.removeListener(this);
priceFeedService.updateCounterProperty().removeListener(priceChangeListener);
hyperlinkWithIcon.setOnAction(null);
}
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onBsqBlockChainChanged() {
issuedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(bsqBlockChain.getIssuedAmountAtGenesis()));
final Coin burntFee = bsqBlockChain.getTotalBurntFee();
final Coin availableAmount = bsqBlockChain.getIssuedAmountAtGenesis().subtract(burntFee);
public void onBlockAdded(BsqBlock bsqBlock) {
updateWithBsqBlockChainData();
}
private void updateWithBsqBlockChainData() {
issuedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(readableBsqBlockChain.getIssuedAmountAtGenesis()));
final Coin burntFee = readableBsqBlockChain.getTotalBurntFee();
final Coin availableAmount = readableBsqBlockChain.getIssuedAmountAtGenesis().subtract(burntFee);
availableAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(availableAmount));
burntAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(burntFee));
allTxTextField.setText(String.valueOf(bsqBlockChain.getTransactions().size()));
utxoTextField.setText(String.valueOf(bsqBlockChain.getUnspentTxOutputs().size()));
spentTxTextField.setText(String.valueOf(bsqBlockChain.getSpentTxOutputs().size()));
burntTxTextField.setText(String.valueOf(bsqBlockChain.getFeeTransactions().size()));
allTxTextField.setText(String.valueOf(readableBsqBlockChain.getTransactions().size()));
utxoTextField.setText(String.valueOf(readableBsqBlockChain.getUnspentTxOutputs().size()));
spentTxTextField.setText(String.valueOf(readableBsqBlockChain.getSpentTxOutputs().size()));
burntTxTextField.setText(String.valueOf(readableBsqBlockChain.getFeeTransactions().size()));
}
private void updatePrice() {
final Coin issuedAmount = bsqBlockChain.getIssuedAmountAtGenesis();
final Coin issuedAmount = readableBsqBlockChain.getIssuedAmountAtGenesis();
final MarketPrice bsqMarketPrice = priceFeedService.getMarketPrice("BSQ");
if (bsqMarketPrice != null) {
long bsqPrice = MathUtils.roundDoubleToLong(MathUtils.scaleUpByPowerOf10(bsqMarketPrice.getPrice(), Altcoin.SMALLEST_UNIT_EXPONENT));

View file

@ -37,6 +37,7 @@ import bisq.core.btc.Restrictions;
import bisq.core.btc.wallet.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletsManager;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.locale.Res;
import bisq.core.util.CoinUtil;
@ -68,6 +69,7 @@ import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqBalanceListener {
private final BsqWalletService bsqWalletService;
private final BtcWalletService btcWalletService;
private final WalletsManager walletsManager;
private final WalletsSetup walletsSetup;
private final P2PService p2PService;
private final BsqFormatter bsqFormatter;
@ -91,6 +93,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
@Inject
private BsqSendView(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService,
WalletsManager walletsManager,
WalletsSetup walletsSetup,
P2PService p2PService,
BsqFormatter bsqFormatter,
@ -101,6 +104,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
BsqAddressValidator bsqAddressValidator) {
this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService;
this.walletsManager = walletsManager;
this.walletsSetup = walletsSetup;
this.p2PService = p2PService;
this.bsqFormatter = bsqFormatter;
@ -155,12 +159,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
bsqFormatter.formatCoinWithCode(receiverAmount)))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> {
bsqWalletService.commitTx(txWithBtcFee);
// We need to create another instance, otherwise the tx would trigger an invalid state exception
// if it gets committed 2 times
btcWalletService.commitTx(btcWalletService.getClonedTransaction(txWithBtcFee));
bsqWalletService.broadcastTx(signedTx, new FutureCallback<Transaction>() {
walletsManager.publishAndCommitBsqTx(txWithBtcFee, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction transaction) {
if (transaction != null) {
@ -173,7 +172,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
log.error(t.toString());
new Popup<>().warning(t.toString());
}
}, 15);
});
receiversAddressInputTextField.setText("");
amountInputTextField.setText("");

View file

@ -25,6 +25,7 @@ import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletService;
import bisq.core.dao.blockchain.vo.Tx;
import bisq.core.dao.blockchain.vo.TxType;
import bisq.core.locale.Res;
@ -38,57 +39,41 @@ import javafx.scene.control.Tooltip;
import java.util.Date;
import java.util.Optional;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import lombok.Data;
import static com.google.common.base.Preconditions.checkNotNull;
@ToString
@Slf4j
@EqualsAndHashCode
@Data
class BsqTxListItem {
@Getter
private final Transaction transaction;
private BsqWalletService bsqWalletService;
private BtcWalletService btcWalletService;
@Getter
private final Date date;
@Getter
private final Optional<Tx> optionalTx;
private final BsqWalletService bsqWalletService;
private final BtcWalletService btcWalletService;
private Date date;
private final String txId;
@Getter
private int confirmations = 0;
@Getter
private final String address;
@Getter
private final String direction;
@Getter
private Coin amount;
@Getter
private boolean received;
@Getter
private Optional<TxType> txTypeOptional;
@Getter
private boolean isBurnedBsqTx;
private BsqFormatter bsqFormatter;
@Getter
private TxConfidenceIndicator txConfidenceIndicator;
private TxConfidenceListener txConfidenceListener;
private boolean issuanceTx;
public BsqTxListItem(Transaction transaction,
BsqTxListItem(Transaction transaction,
Optional<Tx> optionalTx,
BsqWalletService bsqWalletService,
BtcWalletService btcWalletService,
Optional<TxType> txTypeOptional,
boolean isBurnedBsqTx,
Date date,
BsqFormatter bsqFormatter) {
this.transaction = transaction;
this.optionalTx = optionalTx;
this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService;
this.txTypeOptional = txTypeOptional;
this.isBurnedBsqTx = isBurnedBsqTx;
this.date = date;
this.bsqFormatter = bsqFormatter;
@ -174,8 +159,8 @@ class BsqTxListItem {
}
public TxType getTxType() {
if (txTypeOptional.isPresent())
return txTypeOptional.get();
if (optionalTx.isPresent())
return optionalTx.get().getTxType();
else
return confirmations == 0 ? TxType.UNVERIFIED : TxType.UNDEFINED_TX_TYPE;
}

View file

@ -32,14 +32,11 @@ import bisq.core.app.BisqEnvironment;
import bisq.core.btc.wallet.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.DaoPeriodService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.dao.blockchain.vo.Tx;
import bisq.core.dao.blockchain.vo.TxOutput;
import bisq.core.dao.blockchain.vo.TxOutputType;
import bisq.core.dao.blockchain.vo.TxType;
import bisq.core.dao.node.BsqNode;
import bisq.core.dao.node.BsqNodeProvider;
import bisq.core.locale.Res;
import bisq.core.user.Preferences;
@ -77,24 +74,23 @@ import javafx.collections.transformation.SortedList;
import javafx.util.Callback;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@FxmlView
public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBalanceListener {
public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBalanceListener, BsqBlockChain.Listener {
TableView<BsqTxListItem> tableView;
private TableView<BsqTxListItem> tableView;
private Pane rootParent;
private final BsqFormatter bsqFormatter;
private final BsqWalletService bsqWalletService;
private final ReadableBsqBlockChain readableBsqBlockChain;
private final DaoPeriodService daoPeriodService;
private final BtcWalletService btcWalletService;
private final BsqBalanceUtil bsqBalanceUtil;
private final BsqNode bsqNode;
private final Preferences preferences;
private final ObservableList<BsqTxListItem> observableList = FXCollections.observableArrayList();
// Need to be DoubleProperty as we pass it as reference
@ -104,7 +100,6 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
private ListChangeListener<Transaction> walletBsqTransactionsListener;
private int gridRow = 0;
private Label chainHeightLabel;
private BsqNode.BsqBlockChainListener bsqBlockChainListener;
private ProgressBar chainSyncIndicator;
private ChangeListener<Number> chainHeightChangedListener;
@ -116,18 +111,14 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
@Inject
private BsqTxView(BsqFormatter bsqFormatter,
BsqWalletService bsqWalletService,
BsqNodeProvider bsqNodeProvider,
Preferences preferences,
ReadableBsqBlockChain readableBsqBlockChain,
DaoPeriodService daoPeriodService,
BtcWalletService btcWalletService,
BsqBalanceUtil bsqBalanceUtil) {
this.bsqFormatter = bsqFormatter;
this.bsqWalletService = bsqWalletService;
this.bsqNode = bsqNodeProvider.getBsqNode();
this.preferences = preferences;
this.readableBsqBlockChain = readableBsqBlockChain;
this.daoPeriodService = daoPeriodService;
this.btcWalletService = btcWalletService;
this.bsqBalanceUtil = bsqBalanceUtil;
}
@ -172,7 +163,6 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
walletBsqTransactionsListener = change -> updateList();
parentHeightListener = (observable, oldValue, newValue) -> layout();
bsqBlockChainListener = this::onChainHeightChanged;
chainHeightChangedListener = (observable, oldValue, newValue) -> onChainHeightChanged();
}
@ -186,7 +176,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(sortedList);
bsqNode.addBsqBlockChainListener(bsqBlockChainListener);
readableBsqBlockChain.addListener(this);
if (root.getParent() instanceof Pane) {
rootParent = (Pane) root.getParent();
@ -205,7 +195,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
bsqWalletService.getWalletTransactions().removeListener(walletBsqTransactionsListener);
bsqWalletService.removeBsqBalanceListener(this);
btcWalletService.getChainHeightProperty().removeListener(chainHeightChangedListener);
bsqNode.removeBsqBlockChainListener(bsqBlockChainListener);
readableBsqBlockChain.removeListener(this);
observableList.forEach(BsqTxListItem::cleanup);
@ -213,6 +203,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
rootParent.heightProperty().removeListener(parentHeightListener);
}
@Override
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
@ -221,6 +212,17 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
updateList();
}
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onBlockAdded(BsqBlock bsqBlock) {
onChainHeightChanged();
}
private void onChainHeightChanged() {
final int bsqWalletChainHeight = bsqWalletService.getChainHeightProperty().get();
final int bsqBlockChainHeight = readableBsqBlockChain.getChainHeadHeight();
@ -253,71 +255,18 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
// copy list to avoid ConcurrentModificationException
final List<Transaction> walletTransactions = new ArrayList<>(bsqWalletService.getWalletTransactions());
List<BsqTxListItem> items = walletTransactions.stream()
.map(transaction -> new BsqTxListItem(transaction,
.map(transaction -> {
final Optional<Tx> optionalTx = readableBsqBlockChain.getTx(transaction.getHashAsString());
return new BsqTxListItem(transaction,
optionalTx,
bsqWalletService,
btcWalletService,
readableBsqBlockChain.getTxType(transaction.getHashAsString()),
readableBsqBlockChain.hasTxBurntFee(transaction.getHashAsString()),
transaction.getUpdateTime(),
bsqFormatter)
)
.collect(Collectors.toList());
items.addAll(getCompensationRequestTxListItems(items));
observableList.setAll(items);
}
// We add manually a modified copy of the compensation request tx if it has become an issuance tx
// It is a bit weird to have one tx displayed 2 times but I think it is better to show both aspects
// separately. First the compensation request tx with the fee then after voting the issuance.
private List<BsqTxListItem> getCompensationRequestTxListItems(List<BsqTxListItem> items) {
List<BsqTxListItem> issuanceTxList = new ArrayList<>();
items.stream()
.filter(item -> item.getTxType() == TxType.COMPENSATION_REQUEST)
.peek(item -> {
final Tx tx = readableBsqBlockChain.getTx(item.getTxId()).get();
// We have mandatory BSQ change at output 0
long changeValue = tx.getOutputs().get(0).getValue();
long inputValue = tx.getInputs().stream()
.filter(input -> input.getConnectedTxOutput() != null)
.mapToLong(input -> input.getConnectedTxOutput().getValue())
.sum();
// We want to show fee as negative number
long fee = changeValue - inputValue;
item.setAmount(Coin.valueOf(fee));
})
.filter(item -> {
final Optional<Tx> optionalTx = readableBsqBlockChain.getTx(item.getTxId());
if (optionalTx.isPresent()) {
final List<TxOutput> outputs = optionalTx.get().getOutputs();
if (!outputs.isEmpty()) {
return outputs.get(0).getTxOutputType() == TxOutputType.BSQ_OUTPUT;
}
}
return false;
})
.forEach(item -> {
final Tx tx = readableBsqBlockChain.getTx(item.getTxId()).get();
final int blockHeight = tx.getBlockHeight();
final int issuanceBlockHeight = daoPeriodService.getAbsoluteStartBlockOfPhase(blockHeight, DaoPeriodService.Phase.ISSUANCE);
// We use the time of the block height of the start of the issuance period
final long blockTimeInSec = readableBsqBlockChain.getBlockTime(issuanceBlockHeight);
final BsqTxListItem issuanceItem = new BsqTxListItem(item.getTransaction(),
bsqWalletService,
btcWalletService,
Optional.of(TxType.ISSUANCE),
item.isBurnedBsqTx(),
new Date(blockTimeInSec * 1000),
bsqFormatter);
// On output 1 we have the issuance candidate
long issuanceValue = tx.getOutputs().get(1).getValue();
issuanceItem.setAmount(Coin.valueOf(issuanceValue));
issuanceTxList.add(issuanceItem);
});
return issuanceTxList;
})
.collect(Collectors.toList());
observableList.setAll(items);
}
private void layout() {
@ -353,7 +302,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
}
});
tableView.getColumns().add(column);
column.setComparator((o1, o2) -> o1.getDate().compareTo(o2.getDate()));
column.setComparator(Comparator.comparing(BsqTxListItem::getDate));
column.setSortType(TableColumn.SortType.DESCENDING);
tableView.getSortOrder().add(column);
}
@ -414,11 +363,19 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
public void updateItem(final BsqTxListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
TxType txType = item.getTxType();
final TxType txType = item.getTxType();
String labelString = Res.get("dao.tx.type.enum." + txType.name());
Label label;
if (item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal()) {
if (item.isBurnedBsqTx() || item.getAmount().isZero()) {
final Optional<Tx> optionalTx = item.getOptionalTx();
if (txType == TxType.COMPENSATION_REQUEST && optionalTx.isPresent() && optionalTx.get().isIssuanceTx()) {
if (field != null)
field.setOnAction(null);
labelString = Res.get("dao.tx.issuance");
label = new AutoTooltipLabel(labelString);
setGraphic(label);
} else if (item.isBurnedBsqTx() || item.getAmount().isZero()) {
if (field != null)
field.setOnAction(null);
@ -472,11 +429,12 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
@Override
public void updateItem(final BsqTxListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty)
setText(item.getConfirmations() > 0 && item.getTxType().ordinal() > TxType.INVALID.ordinal() ?
if (item != null && !empty) {
TxType txType = item.getTxType();
setText(item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal() ?
bsqFormatter.formatCoin(item.getAmount()) :
Res.get("shared.na"));
else
} else
setText("");
}
};
@ -570,8 +528,15 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
style = "dao-tx-type-default-icon";
break;
case COMPENSATION_REQUEST:
if (item.getOptionalTx().isPresent() && item.getOptionalTx().get().isIssuanceTx()) {
awesomeIcon = AwesomeIcon.MONEY;
style = "dao-tx-type-issuance-icon";
long blockTimeInSec = readableBsqBlockChain.getBlockTime(item.getOptionalTx().get().getIssuanceBlockHeight());
toolTipText = Res.get("dao.tx.issuance.tooltip", bsqFormatter.formatDateTime(new Date(blockTimeInSec * 1000)));
} else {
awesomeIcon = AwesomeIcon.FILE;
style = "dao-tx-type-fee-icon";
}
break;
case BLIND_VOTE:
awesomeIcon = AwesomeIcon.THUMBS_UP;
@ -581,10 +546,6 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
awesomeIcon = AwesomeIcon.LIGHTBULB;
style = "dao-tx-type-vote-reveal-icon";
break;
case ISSUANCE:
awesomeIcon = AwesomeIcon.MONEY;
style = "dao-tx-type-issuance-icon";
break;
default:
awesomeIcon = AwesomeIcon.QUESTION_SIGN;
style = "dao-tx-type-unverified-icon";

View file

@ -21,7 +21,7 @@ import bisq.desktop.util.BSFormatter;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.trade.Tradable;
import org.bitcoinj.core.Transaction;
@ -35,15 +35,15 @@ import javax.annotation.Nullable;
public class TransactionListItemFactory {
private final BtcWalletService btcWalletService;
private final BsqWalletService bsqWalletService;
private final BsqBlockChain bsqBlockChain;
private final ReadableBsqBlockChain readableBsqBlockChain;
private final BSFormatter formatter;
@Inject
TransactionListItemFactory(BtcWalletService btcWalletService, BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain, BSFormatter formatter) {
ReadableBsqBlockChain readableBsqBlockChain, BSFormatter formatter) {
this.btcWalletService = btcWalletService;
this.bsqWalletService = bsqWalletService;
this.bsqBlockChain = bsqBlockChain;
this.readableBsqBlockChain = readableBsqBlockChain;
this.formatter = formatter;
}
@ -51,6 +51,6 @@ public class TransactionListItemFactory {
Optional<Tradable> maybeTradable = Optional.ofNullable(tradable)
.map(TransactionAwareTradable::asTradable);
return new TransactionsListItem(transaction, btcWalletService, bsqWalletService, maybeTradable, bsqBlockChain, formatter);
return new TransactionsListItem(transaction, btcWalletService, bsqWalletService, maybeTradable, readableBsqBlockChain, formatter);
}
}

View file

@ -26,7 +26,7 @@ import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.TxType;
import bisq.core.locale.Res;
import bisq.core.offer.Offer;
@ -80,7 +80,7 @@ class TransactionsListItem {
BtcWalletService btcWalletService,
BsqWalletService bsqWalletService,
Optional<Tradable> tradableOptional,
BsqBlockChain bsqBlockChain,
ReadableBsqBlockChain readableBsqBlockChain,
BSFormatter formatter) {
this.formatter = formatter;
txId = transaction.getHashAsString();
@ -130,7 +130,7 @@ class TransactionsListItem {
txFeeForBsqPayment = true;
//
final Optional<TxType> txTypeOptional = bsqBlockChain.getTxType(txId);
final Optional<TxType> txTypeOptional = readableBsqBlockChain.getTxType(txId);
if (txTypeOptional.isPresent() && txTypeOptional.get().equals(TxType.COMPENSATION_REQUEST))
details = Res.get("funds.tx.proposal");
} else {

View file

@ -211,7 +211,7 @@ public class BuyerStep4View extends TradeStepView {
} else {
if (toAddresses.isEmpty()) {
validateWithdrawAddress();
} else if (Restrictions.isAboveDust(amount, fee)) {
} else if (Restrictions.isAboveDust(receiverAmount)) {
BSFormatter formatter = model.btcFormatter;
int txSize = feeEstimationTransaction.bitcoinSerialize().length;
double feePerByte = CoinUtil.getFeePerByte(fee, txSize);