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

View file

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

View file

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

View file

@ -22,7 +22,7 @@ import bisq.desktop.util.BsqFormatter;
import bisq.desktop.util.Layout; import bisq.desktop.util.Layout;
import bisq.core.btc.wallet.BsqWalletService; 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 bisq.core.locale.Res;
import javafx.geometry.Insets; import javafx.geometry.Insets;

View file

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

View file

@ -23,15 +23,15 @@ import bisq.desktop.util.BsqFormatter;
import bisq.core.btc.listeners.TxConfidenceListener; import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService; 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.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.dao.blockchain.vo.Tx; 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.BooleanVoteResult;
import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.dao.vote.VoteResult; 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 bisq.core.locale.Res;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -54,14 +54,13 @@ import lombok.extern.slf4j.Slf4j;
@ToString @ToString
@Slf4j @Slf4j
@EqualsAndHashCode @EqualsAndHashCode
public class ProposalListItem implements BsqNode.BsqBlockChainListener { public class ProposalListItem implements BsqBlockChain.Listener {
@Getter @Getter
private final Proposal proposal; private final Proposal proposal;
private final ProposalCollectionsService proposalCollectionsService; private final ProposalService proposalService;
private final DaoPeriodService daoPeriodService; private final DaoPeriodService daoPeriodService;
private final BsqWalletService bsqWalletService; private final BsqWalletService bsqWalletService;
private final ReadableBsqBlockChain readableBsqBlockChain; private final ReadableBsqBlockChain readableBsqBlockChain;
private final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
private final BsqFormatter bsqFormatter; private final BsqFormatter bsqFormatter;
private final ChangeListener<Number> chainHeightListener; private final ChangeListener<Number> chainHeightListener;
private final ChangeListener<VoteResult> voteResultChangeListener; private final ChangeListener<VoteResult> voteResultChangeListener;
@ -81,18 +80,16 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
private Node actionNode; private Node actionNode;
ProposalListItem(Proposal proposal, ProposalListItem(Proposal proposal,
ProposalCollectionsService proposalCollectionsService, ProposalService proposalService,
DaoPeriodService daoPeriodService, DaoPeriodService daoPeriodService,
BsqWalletService bsqWalletService, BsqWalletService bsqWalletService,
ReadableBsqBlockChain readableBsqBlockChain, ReadableBsqBlockChain readableBsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
BsqFormatter bsqFormatter) { BsqFormatter bsqFormatter) {
this.proposal = proposal; this.proposal = proposal;
this.proposalCollectionsService = proposalCollectionsService; this.proposalService = proposalService;
this.daoPeriodService = daoPeriodService; this.daoPeriodService = daoPeriodService;
this.bsqWalletService = bsqWalletService; this.bsqWalletService = bsqWalletService;
this.readableBsqBlockChain = readableBsqBlockChain; this.readableBsqBlockChain = readableBsqBlockChain;
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
this.bsqFormatter = bsqFormatter; this.bsqFormatter = bsqFormatter;
@ -111,7 +108,7 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener); bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
setupConfidence(); setupConfidence();
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this); readableBsqBlockChain.addListener(this);
phaseChangeListener = (observable, oldValue, newValue) -> { phaseChangeListener = (observable, oldValue, newValue) -> {
applyState(newValue, proposal.getVoteResult()); applyState(newValue, proposal.getVoteResult());
@ -134,7 +131,7 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
case UNDEFINED: case UNDEFINED:
break; break;
case PROPOSAL: case PROPOSAL:
if (proposalCollectionsService.isMine(proposal)) { if (proposalService.isMine(proposal)) {
actionButton.setVisible(!isTxInPastCycle); actionButton.setVisible(!isTxInPastCycle);
actionButtonIconView.setVisible(actionButton.isVisible()); actionButtonIconView.setVisible(actionButton.isVisible());
actionButton.setText(Res.get("shared.remove")); actionButton.setText(Res.get("shared.remove"));
@ -188,11 +185,18 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
//actionButtonIconView.setManaged(actionButtonIconView.isVisible()); //actionButtonIconView.setManaged(actionButtonIconView.isVisible());
} }
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public void onBsqBlockChainChanged() { public void onBlockAdded(BsqBlock bsqBlock) {
//TODO do we want that here???
setupConfidence(); setupConfidence();
} }
private void setupConfidence() { private void setupConfidence() {
final Tx tx = readableBsqBlockChain.getTxMap().get(proposal.getProposalPayload().getTxId()); final Tx tx = readableBsqBlockChain.getTxMap().get(proposal.getProposalPayload().getTxId());
if (tx != null) { if (tx != null) {
@ -238,7 +242,7 @@ public class ProposalListItem implements BsqNode.BsqBlockChainListener {
} }
public void cleanup() { public void cleanup() {
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this); readableBsqBlockChain.removeListener(this);
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener); bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
if (txConfidenceListener != null) if (txConfidenceListener != null)
bsqWalletService.removeTxConfidenceListener(txConfidenceListener); 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.exceptions.WalletException;
import bisq.core.btc.wallet.BsqBalanceListener; import bisq.core.btc.wallet.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.ChangeBelowDustException;
import bisq.core.btc.wallet.InsufficientBsqException; import bisq.core.btc.wallet.InsufficientBsqException;
import bisq.core.dao.DaoPeriodService; import bisq.core.dao.blockchain.ReadableBsqBlockChain;
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.vote.BooleanVoteResult; 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.core.locale.Res;
import bisq.common.crypto.CryptoException; import bisq.common.crypto.CryptoException;
@ -66,6 +64,8 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.util.Callback; import javafx.util.Callback;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -82,7 +82,7 @@ import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
@FxmlView @FxmlView
public class ActiveProposalsView extends BaseProposalView implements BsqBalanceListener { public class ActiveProposalsView extends BaseProposalView implements BsqBalanceListener {
private final VoteService voteService; private final BlindVoteService blindVoteService;
private Button removeButton, acceptButton, rejectButton, cancelVoteButton, voteButton; private Button removeButton, acceptButton, rejectButton, cancelVoteButton, voteButton;
private InputTextField stakeInputTextField; private InputTextField stakeInputTextField;
@ -94,16 +94,15 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
private ActiveProposalsView(ProposalCollectionsService voteRequestManger, private ActiveProposalsView(ProposalService voteRequestManger,
DaoPeriodService daoPeriodService, DaoPeriodService daoPeriodService,
VoteService voteService, BlindVoteService blindVoteService,
BsqWalletService bsqWalletService, BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain, ReadableBsqBlockChain readableBsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
BsqFormatter bsqFormatter) { BsqFormatter bsqFormatter) {
super(voteRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService, super(voteRequestManger, bsqWalletService, readableBsqBlockChain, daoPeriodService,
bsqFormatter); bsqFormatter);
this.voteService = voteService; this.blindVoteService = blindVoteService;
} }
@Override @Override
@ -133,7 +132,7 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
// TODO verify stake // TODO verify stake
//TODO show popup //TODO show popup
try { try {
voteService.publishBlindVote(stake, new FutureCallback<Transaction>() { blindVoteService.publishBlindVote(stake, new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(@Nullable Transaction result) { public void onSuccess(@Nullable Transaction result) {
//TODO //TODO
@ -155,10 +154,10 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
e1.printStackTrace(); e1.printStackTrace();
} catch (InsufficientMoneyException e1) { } catch (InsufficientMoneyException e1) {
e1.printStackTrace(); e1.printStackTrace();
} catch (ChangeBelowDustException e1) {
e1.printStackTrace();
} catch (InvalidProtocolBufferException e1) { } catch (InvalidProtocolBufferException e1) {
e1.printStackTrace(); e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} }
}); });
} }
@ -268,7 +267,7 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
final Proposal proposal = selectedProposalListItem.getProposal(); final Proposal proposal = selectedProposalListItem.getProposal();
switch (phase) { switch (phase) {
case PROPOSAL: case PROPOSAL:
if (proposalCollectionsService.isMine(proposal)) { if (proposalService.isMine(proposal)) {
if (removeButton == null) { if (removeButton == null) {
removeButton = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.active.remove")); removeButton = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.active.remove"));
removeButton.setOnAction(event -> onRemove()); removeButton.setOnAction(event -> onRemove());
@ -327,12 +326,12 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
@Override @Override
protected void updateProposalList() { protected void updateProposalList() {
doUpdateProposalList(proposalCollectionsService.getActiveProposals()); doUpdateProposalList(proposalService.getActiveProposals());
} }
private void updateStateAfterVote() { private void updateStateAfterVote() {
hideProposalDisplay(); hideProposalDisplay();
proposalCollectionsService.persist(); proposalService.persist();
proposalTableView.getSelectionModel().clearSelection(); proposalTableView.getSelectionModel().clearSelection();
} }
@ -344,7 +343,7 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL
} }
private void onRemove() { private void onRemove() {
if (proposalCollectionsService.removeProposal(selectedProposalListItem.getProposal())) if (proposalService.removeProposal(selectedProposalListItem.getProposal()))
hideProposalDisplay(); hideProposalDisplay();
else else
new Popup<>().warning(Res.get("dao.proposal.active.remove.failed")).show(); 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.desktop.util.BsqFormatter;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoPeriodService; import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.BsqBlockChain; import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher; import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.dao.proposal.ProposalCollectionsService;
import javax.inject.Inject; import javax.inject.Inject;
@ -37,14 +36,12 @@ public class ClosedProposalsView extends BaseProposalView {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
private ClosedProposalsView(ProposalCollectionsService proposalCollectionsService, private ClosedProposalsView(ProposalService proposalService,
DaoPeriodService daoPeriodService, DaoPeriodService daoPeriodService,
BsqWalletService bsqWalletService, BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain, ReadableBsqBlockChain readableBsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
BsqFormatter bsqFormatter) { BsqFormatter bsqFormatter) {
super(proposalCollectionsService, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService, super(proposalService, bsqWalletService, readableBsqBlockChain, daoPeriodService, bsqFormatter);
bsqFormatter);
} }
@Override @Override
@ -67,7 +64,7 @@ public class ClosedProposalsView extends BaseProposalView {
@Override @Override
protected void updateProposalList() { 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.desktop.util.Layout;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoPeriodService; import bisq.core.dao.vote.DaoPeriodService;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import javax.inject.Inject; 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.TransactionVerificationException;
import bisq.core.btc.exceptions.WalletException; import bisq.core.btc.exceptions.WalletException;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.ChangeBelowDustException;
import bisq.core.btc.wallet.InsufficientBsqException; import bisq.core.btc.wallet.InsufficientBsqException;
import bisq.core.btc.wallet.WalletsSetup; import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.blockchain.ReadableBsqBlockChain; import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.proposal.Proposal; import bisq.core.dao.vote.proposal.Proposal;
import bisq.core.dao.proposal.ProposalCollectionsService; import bisq.core.dao.vote.proposal.ProposalConsensus;
import bisq.core.dao.proposal.ProposalType; import bisq.core.dao.vote.proposal.ProposalService;
import bisq.core.dao.proposal.compensation.CompensationAmountException; import bisq.core.dao.vote.proposal.ProposalType;
import bisq.core.dao.proposal.compensation.CompensationRequestPayload; import bisq.core.dao.vote.proposal.ValidationException;
import bisq.core.dao.proposal.compensation.CompensationRequestService; import bisq.core.dao.vote.proposal.compensation.CompensationRequestPayload;
import bisq.core.dao.proposal.consensus.ProposalConsensus; import bisq.core.dao.vote.proposal.compensation.CompensationRequestService;
import bisq.core.dao.proposal.generic.GenericProposalPayload; import bisq.core.dao.vote.proposal.generic.GenericProposalPayload;
import bisq.core.dao.proposal.generic.GenericProposalService; import bisq.core.dao.vote.proposal.generic.GenericProposalService;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.provider.fee.FeeService; import bisq.core.provider.fee.FeeService;
import bisq.core.util.CoinUtil; import bisq.core.util.CoinUtil;
@ -68,6 +67,8 @@ import javafx.collections.FXCollections;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
@ -90,7 +91,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
private final WalletsSetup walletsSetup; private final WalletsSetup walletsSetup;
private final P2PService p2PService; private final P2PService p2PService;
private final FeeService feeService; private final FeeService feeService;
private final ProposalCollectionsService proposalCollectionsService; private final ProposalService proposalService;
private final CompensationRequestService compensationRequestService; private final CompensationRequestService compensationRequestService;
private final GenericProposalService genericProposalService; private final GenericProposalService genericProposalService;
private final ReadableBsqBlockChain readableBsqBlockChain; private final ReadableBsqBlockChain readableBsqBlockChain;
@ -110,7 +111,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
WalletsSetup walletsSetup, WalletsSetup walletsSetup,
P2PService p2PService, P2PService p2PService,
FeeService feeService, FeeService feeService,
ProposalCollectionsService proposalCollectionsService, ProposalService proposalService,
CompensationRequestService compensationRequestService, CompensationRequestService compensationRequestService,
GenericProposalService genericProposalService, GenericProposalService genericProposalService,
ReadableBsqBlockChain readableBsqBlockChain, ReadableBsqBlockChain readableBsqBlockChain,
@ -120,7 +121,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
this.walletsSetup = walletsSetup; this.walletsSetup = walletsSetup;
this.p2PService = p2PService; this.p2PService = p2PService;
this.feeService = feeService; this.feeService = feeService;
this.proposalCollectionsService = proposalCollectionsService; this.proposalService = proposalService;
this.compensationRequestService = compensationRequestService; this.compensationRequestService = compensationRequestService;
this.genericProposalService = genericProposalService; this.genericProposalService = genericProposalService;
this.readableBsqBlockChain = readableBsqBlockChain; this.readableBsqBlockChain = readableBsqBlockChain;
@ -176,33 +177,31 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
Coin miningFee = Objects.requireNonNull(tx).getFee(); Coin miningFee = Objects.requireNonNull(tx).getFee();
int txSize = tx.bitcoinSerialize().length; int txSize = tx.bitcoinSerialize().length;
validateInputs();
new Popup<>().headLine(Res.get("dao.proposal.create.confirm")) new Popup<>().headLine(Res.get("dao.proposal.create.confirm"))
.confirmation(Res.get("dao.proposal.create.confirm.info", .confirmation(Res.get("dao.proposal.create.confirm.info",
bsqFormatter.formatCoinWithCode( bsqFormatter.formatCoinWithCode(ProposalConsensus.getFee(readableBsqBlockChain)),
ProposalConsensus.getCreateCompensationRequestFee(readableBsqBlockChain)),
btcFormatter.formatCoinWithCode(miningFee), btcFormatter.formatCoinWithCode(miningFee),
CoinUtil.getFeePerByte(miningFee, txSize), CoinUtil.getFeePerByte(miningFee, txSize),
(txSize / 1000d))) txSize / 1000d))
.actionButtonText(Res.get("shared.yes")) .actionButtonText(Res.get("shared.yes"))
.onAction(() -> { .onAction(() -> {
proposalCollectionsService.publishProposal(proposal, new FutureCallback<Transaction>() { proposalService.publishProposal(proposal,
@Override new FutureCallback<Transaction>() {
public void onSuccess(@Nullable Transaction transaction) { @Override
proposalDisplay.clearForm(); public void onSuccess(@Nullable Transaction transaction) {
proposalDisplay.clearForm();
proposalTypeComboBox.getSelectionModel().clearSelection(); proposalTypeComboBox.getSelectionModel().clearSelection();
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show(); new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
} }
@Override @Override
public void onFailure(@NotNull Throwable t) { public void onFailure(@NotNull Throwable t) {
log.error(t.toString()); log.error(t.toString());
new Popup<>().warning(t.toString()).show(); new Popup<>().warning(t.toString()).show();
} }
}); });
}) })
.closeButtonText(Res.get("shared.cancel")) .closeButtonText(Res.get("shared.cancel"))
.show(); .show();
@ -210,37 +209,45 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter; BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter;
new Popup<>().warning(Res.get("dao.proposal.create.missingFunds", new Popup<>().warning(Res.get("dao.proposal.create.missingFunds",
formatter.formatCoinWithCode(e.missing))).show(); formatter.formatCoinWithCode(e.missing))).show();
} catch (CompensationAmountException e) { } catch (ValidationException e) {
new Popup<>().warning(Res.get("validation.bsq.amountBelowMinAmount", String message;
bsqFormatter.formatCoinWithCode(e.required))).show(); if (e.getMinRequestAmount() != null) {
} catch (TransactionVerificationException | WalletException e) { 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()); log.error(e.toString());
e.printStackTrace(); e.printStackTrace();
new Popup<>().warning(e.toString()).show(); 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) { switch (type) {
case COMPENSATION_REQUEST: case COMPENSATION_REQUEST:
CompensationRequestPayload compensationRequestPayload = compensationRequestService.getNewCompensationRequestPayload( CompensationRequestPayload compensationRequestPayload = compensationRequestService.getCompensationRequestPayload(
proposalDisplay.nameTextField.getText(), proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(), proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(), proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText(), proposalDisplay.linkInputTextField.getText(),
bsqFormatter.parseToCoin(Objects.requireNonNull(proposalDisplay.requestedBsqTextField).getText()), bsqFormatter.parseToCoin(Objects.requireNonNull(proposalDisplay.requestedBsqTextField).getText()),
Objects.requireNonNull(proposalDisplay.bsqAddressTextField).getText()); Objects.requireNonNull(proposalDisplay.bsqAddressTextField).getText());
return compensationRequestService.prepareCompensationRequest(compensationRequestPayload); return compensationRequestService.getCompensationRequest(compensationRequestPayload);
case GENERIC: case GENERIC:
GenericProposalPayload genericProposalPayload = genericProposalService.getNewGenericProposalPayload( GenericProposalPayload genericProposalPayload = genericProposalService.getGenericProposalPayload(
proposalDisplay.nameTextField.getText(), proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(), proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(), proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText()); proposalDisplay.linkInputTextField.getText());
return genericProposalService.prepareGenericProposal(genericProposalPayload); return genericProposalService.getGenericProposal(genericProposalPayload);
case CHANGE_PARAM: case CHANGE_PARAM:
//TODO //TODO
return null; return null;

View file

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

View file

@ -22,11 +22,11 @@ import bisq.desktop.util.BsqFormatter;
import bisq.core.btc.listeners.TxConfidenceListener; import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.ReadableBsqBlockChain; 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.Tx;
import bisq.core.dao.blockchain.vo.TxOutput; 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.dao.vote.MyVote;
import bisq.core.locale.Res; import bisq.core.locale.Res;
@ -51,7 +51,7 @@ import lombok.extern.slf4j.Slf4j;
@ToString @ToString
@Slf4j @Slf4j
@EqualsAndHashCode @EqualsAndHashCode
public class VoteListItem implements BsqNode.BsqBlockChainListener { public class VoteListItem implements BsqBlockChain.Listener {
@Getter @Getter
private final MyVote myVote; private final MyVote myVote;
private final BsqWalletService bsqWalletService; private final BsqWalletService bsqWalletService;
@ -76,7 +76,6 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
VoteListItem(MyVote myVote, VoteListItem(MyVote myVote,
BsqWalletService bsqWalletService, BsqWalletService bsqWalletService,
ReadableBsqBlockChain readableBsqBlockChain, ReadableBsqBlockChain readableBsqBlockChain,
BsqNodeProvider bsqNodeProvider,
BsqFormatter bsqFormatter) { BsqFormatter bsqFormatter) {
this.myVote = myVote; this.myVote = myVote;
this.bsqWalletService = bsqWalletService; this.bsqWalletService = bsqWalletService;
@ -89,7 +88,7 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
txConfidenceIndicator.setProgress(-1); txConfidenceIndicator.setProgress(-1);
txConfidenceIndicator.setPrefSize(24, 24); txConfidenceIndicator.setPrefSize(24, 24);
txConfidenceIndicator.setTooltip(tooltip); txConfidenceIndicator.setTooltip(tooltip);
bsqNodeProvider.getBsqNode().addBsqBlockChainListener(this); readableBsqBlockChain.addListener(this);
chainHeightListener = (observable, oldValue, newValue) -> setupConfidence(); chainHeightListener = (observable, oldValue, newValue) -> setupConfidence();
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener); bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
@ -97,12 +96,18 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
calculateStake(); calculateStake();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public void onBsqBlockChainChanged() { public void onBlockAdded(BsqBlock bsqBlock) {
//TODO do we want that here???
setupConfidence(); setupConfidence();
calculateStake();
} }
private void setupConfidence() { private void setupConfidence() {
calculateStake(); calculateStake();
final Tx tx = readableBsqBlockChain.getTxMap().get(myVote.getBlindVote().getTxId()); final Tx tx = readableBsqBlockChain.getTxMap().get(myVote.getBlindVote().getTxId());
@ -144,7 +149,7 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
private void calculateStake() { private void calculateStake() {
if (stake == 0) { if (stake == 0) {
String txId = myVote.getTxId(); String txId = myVote.getTxId();
stake = readableBsqBlockChain.getLockedForVoteTxOutputs().stream() stake = readableBsqBlockChain.getBlindVoteStakeTxOutputs().stream()
.filter(txOutput -> txOutput.getTxId().equals(txId)) .filter(txOutput -> txOutput.getTxId().equals(txId))
.filter(txOutput -> txOutput.getIndex() == 0) .filter(txOutput -> txOutput.getIndex() == 0)
.mapToLong(TxOutput::getValue) .mapToLong(TxOutput::getValue)
@ -162,9 +167,9 @@ public class VoteListItem implements BsqNode.BsqBlockChainListener {
public void cleanup() { public void cleanup() {
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener); bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
readableBsqBlockChain.removeListener(this);
if (txConfidenceListener != null) if (txConfidenceListener != null)
bsqWalletService.removeTxConfidenceListener(txConfidenceListener); bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
} }
private void updateConfidence(TransactionConfidence.ConfidenceType confidenceType, int depthInBlocks, int numBroadcastPeers) { 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.desktop.util.Layout;
import bisq.core.dao.blockchain.BsqBlockChain; import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.node.BsqNode; import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.node.BsqNodeProvider; import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.monetary.Altcoin; import bisq.core.monetary.Altcoin;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
@ -57,11 +57,10 @@ import static bisq.desktop.util.FormBuilder.addLabelTextField;
import static bisq.desktop.util.FormBuilder.addTitledGroupBg; import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
@FxmlView @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 BsqBalanceUtil bsqBalanceUtil;
private final BsqNode bsqNode; private final ReadableBsqBlockChain readableBsqBlockChain;
private final BsqBlockChain bsqBlockChain;
private final PriceFeedService priceFeedService; private final PriceFeedService priceFeedService;
private final Preferences preferences; private final Preferences preferences;
private final BsqFormatter bsqFormatter; private final BsqFormatter bsqFormatter;
@ -80,14 +79,12 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
@Inject @Inject
private BsqDashboardView(BsqBalanceUtil bsqBalanceUtil, private BsqDashboardView(BsqBalanceUtil bsqBalanceUtil,
BsqNodeProvider bsqNodeProvider, ReadableBsqBlockChain readableBsqBlockChain,
BsqBlockChain bsqBlockChain,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
Preferences preferences, Preferences preferences,
BsqFormatter bsqFormatter) { BsqFormatter bsqFormatter) {
this.bsqBalanceUtil = bsqBalanceUtil; this.bsqBalanceUtil = bsqBalanceUtil;
this.bsqNode = bsqNodeProvider.getBsqNode(); this.readableBsqBlockChain = readableBsqBlockChain;
this.bsqBlockChain = bsqBlockChain;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.preferences = preferences; this.preferences = preferences;
this.bsqFormatter = bsqFormatter; 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); addTitledGroupBg(root, ++gridRow, 12, Res.get("dao.wallet.dashboard.statistics"), Layout.GROUP_DISTANCE);
addLabelTextField(root, gridRow, Res.get("dao.wallet.dashboard.genesisBlockHeight"), 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")); Label label = new AutoTooltipLabel(Res.get("dao.wallet.dashboard.genesisTxId"));
GridPane.setRowIndex(label, ++gridRow); GridPane.setRowIndex(label, ++gridRow);
root.getChildren().add(label); root.getChildren().add(label);
hyperlinkWithIcon = new HyperlinkWithIcon(bsqBlockChain.getGenesisTxId(), AwesomeIcon.EXTERNAL_LINK); hyperlinkWithIcon = new HyperlinkWithIcon(readableBsqBlockChain.getGenesisTxId(), AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", bsqBlockChain.getGenesisTxId()))); hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", readableBsqBlockChain.getGenesisTxId())));
GridPane.setRowIndex(hyperlinkWithIcon, gridRow); GridPane.setRowIndex(hyperlinkWithIcon, gridRow);
GridPane.setColumnIndex(hyperlinkWithIcon, 1); GridPane.setColumnIndex(hyperlinkWithIcon, 1);
GridPane.setMargin(hyperlinkWithIcon, new Insets(0, 0, 0, -4)); GridPane.setMargin(hyperlinkWithIcon, new Insets(0, 0, 0, -4));
@ -131,39 +128,48 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
protected void activate() { protected void activate() {
bsqBalanceUtil.activate(); bsqBalanceUtil.activate();
bsqNode.addBsqBlockChainListener(this); readableBsqBlockChain.addListener(this);
priceFeedService.updateCounterProperty().addListener(priceChangeListener); 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(); updatePrice();
} }
@Override @Override
protected void deactivate() { protected void deactivate() {
bsqBalanceUtil.deactivate(); bsqBalanceUtil.deactivate();
bsqNode.removeBsqBlockChainListener(this); readableBsqBlockChain.removeListener(this);
priceFeedService.updateCounterProperty().removeListener(priceChangeListener); priceFeedService.updateCounterProperty().removeListener(priceChangeListener);
hyperlinkWithIcon.setOnAction(null); hyperlinkWithIcon.setOnAction(null);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public void onBsqBlockChainChanged() { public void onBlockAdded(BsqBlock bsqBlock) {
issuedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(bsqBlockChain.getIssuedAmountAtGenesis())); updateWithBsqBlockChainData();
final Coin burntFee = bsqBlockChain.getTotalBurntFee(); }
final Coin availableAmount = bsqBlockChain.getIssuedAmountAtGenesis().subtract(burntFee);
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)); availableAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(availableAmount));
burntAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(burntFee)); burntAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(burntFee));
allTxTextField.setText(String.valueOf(bsqBlockChain.getTransactions().size())); allTxTextField.setText(String.valueOf(readableBsqBlockChain.getTransactions().size()));
utxoTextField.setText(String.valueOf(bsqBlockChain.getUnspentTxOutputs().size())); utxoTextField.setText(String.valueOf(readableBsqBlockChain.getUnspentTxOutputs().size()));
spentTxTextField.setText(String.valueOf(bsqBlockChain.getSpentTxOutputs().size())); spentTxTextField.setText(String.valueOf(readableBsqBlockChain.getSpentTxOutputs().size()));
burntTxTextField.setText(String.valueOf(bsqBlockChain.getFeeTransactions().size())); burntTxTextField.setText(String.valueOf(readableBsqBlockChain.getFeeTransactions().size()));
} }
private void updatePrice() { private void updatePrice() {
final Coin issuedAmount = bsqBlockChain.getIssuedAmountAtGenesis(); final Coin issuedAmount = readableBsqBlockChain.getIssuedAmountAtGenesis();
final MarketPrice bsqMarketPrice = priceFeedService.getMarketPrice("BSQ"); final MarketPrice bsqMarketPrice = priceFeedService.getMarketPrice("BSQ");
if (bsqMarketPrice != null) { if (bsqMarketPrice != null) {
long bsqPrice = MathUtils.roundDoubleToLong(MathUtils.scaleUpByPowerOf10(bsqMarketPrice.getPrice(), Altcoin.SMALLEST_UNIT_EXPONENT)); 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.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletsManager;
import bisq.core.btc.wallet.WalletsSetup; import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.util.CoinUtil; 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 { public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqBalanceListener {
private final BsqWalletService bsqWalletService; private final BsqWalletService bsqWalletService;
private final BtcWalletService btcWalletService; private final BtcWalletService btcWalletService;
private final WalletsManager walletsManager;
private final WalletsSetup walletsSetup; private final WalletsSetup walletsSetup;
private final P2PService p2PService; private final P2PService p2PService;
private final BsqFormatter bsqFormatter; private final BsqFormatter bsqFormatter;
@ -91,6 +93,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
@Inject @Inject
private BsqSendView(BsqWalletService bsqWalletService, private BsqSendView(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
WalletsManager walletsManager,
WalletsSetup walletsSetup, WalletsSetup walletsSetup,
P2PService p2PService, P2PService p2PService,
BsqFormatter bsqFormatter, BsqFormatter bsqFormatter,
@ -101,6 +104,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
BsqAddressValidator bsqAddressValidator) { BsqAddressValidator bsqAddressValidator) {
this.bsqWalletService = bsqWalletService; this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService; this.btcWalletService = btcWalletService;
this.walletsManager = walletsManager;
this.walletsSetup = walletsSetup; this.walletsSetup = walletsSetup;
this.p2PService = p2PService; this.p2PService = p2PService;
this.bsqFormatter = bsqFormatter; this.bsqFormatter = bsqFormatter;
@ -155,12 +159,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
bsqFormatter.formatCoinWithCode(receiverAmount))) bsqFormatter.formatCoinWithCode(receiverAmount)))
.actionButtonText(Res.get("shared.yes")) .actionButtonText(Res.get("shared.yes"))
.onAction(() -> { .onAction(() -> {
bsqWalletService.commitTx(txWithBtcFee); walletsManager.publishAndCommitBsqTx(txWithBtcFee, new FutureCallback<Transaction>() {
// 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>() {
@Override @Override
public void onSuccess(@Nullable Transaction transaction) { public void onSuccess(@Nullable Transaction transaction) {
if (transaction != null) { if (transaction != null) {
@ -173,7 +172,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
log.error(t.toString()); log.error(t.toString());
new Popup<>().warning(t.toString()); new Popup<>().warning(t.toString());
} }
}, 15); });
receiversAddressInputTextField.setText(""); receiversAddressInputTextField.setText("");
amountInputTextField.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.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletService; import bisq.core.btc.wallet.WalletService;
import bisq.core.dao.blockchain.vo.Tx;
import bisq.core.dao.blockchain.vo.TxType; import bisq.core.dao.blockchain.vo.TxType;
import bisq.core.locale.Res; import bisq.core.locale.Res;
@ -38,57 +39,41 @@ import javafx.scene.control.Tooltip;
import java.util.Date; import java.util.Date;
import java.util.Optional; import java.util.Optional;
import lombok.EqualsAndHashCode; import lombok.Data;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ToString @Data
@Slf4j
@EqualsAndHashCode
class BsqTxListItem { class BsqTxListItem {
@Getter
private final Transaction transaction; private final Transaction transaction;
private BsqWalletService bsqWalletService; private final Optional<Tx> optionalTx;
private BtcWalletService btcWalletService; private final BsqWalletService bsqWalletService;
@Getter private final BtcWalletService btcWalletService;
private final Date date; private Date date;
@Getter
private final String txId; private final String txId;
@Getter
private int confirmations = 0; private int confirmations = 0;
@Getter
private final String address; private final String address;
@Getter
private final String direction; private final String direction;
@Getter
private Coin amount; private Coin amount;
@Getter
private boolean received; private boolean received;
@Getter
private Optional<TxType> txTypeOptional;
@Getter
private boolean isBurnedBsqTx; private boolean isBurnedBsqTx;
private BsqFormatter bsqFormatter; private BsqFormatter bsqFormatter;
@Getter
private TxConfidenceIndicator txConfidenceIndicator; private TxConfidenceIndicator txConfidenceIndicator;
private TxConfidenceListener txConfidenceListener; private TxConfidenceListener txConfidenceListener;
private boolean issuanceTx;
public BsqTxListItem(Transaction transaction, BsqTxListItem(Transaction transaction,
BsqWalletService bsqWalletService, Optional<Tx> optionalTx,
BtcWalletService btcWalletService, BsqWalletService bsqWalletService,
Optional<TxType> txTypeOptional, BtcWalletService btcWalletService,
boolean isBurnedBsqTx, boolean isBurnedBsqTx,
Date date, Date date,
BsqFormatter bsqFormatter) { BsqFormatter bsqFormatter) {
this.transaction = transaction; this.transaction = transaction;
this.optionalTx = optionalTx;
this.bsqWalletService = bsqWalletService; this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService; this.btcWalletService = btcWalletService;
this.txTypeOptional = txTypeOptional;
this.isBurnedBsqTx = isBurnedBsqTx; this.isBurnedBsqTx = isBurnedBsqTx;
this.date = date; this.date = date;
this.bsqFormatter = bsqFormatter; this.bsqFormatter = bsqFormatter;
@ -174,8 +159,8 @@ class BsqTxListItem {
} }
public TxType getTxType() { public TxType getTxType() {
if (txTypeOptional.isPresent()) if (optionalTx.isPresent())
return txTypeOptional.get(); return optionalTx.get().getTxType();
else else
return confirmations == 0 ? TxType.UNVERIFIED : TxType.UNDEFINED_TX_TYPE; 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.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; 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.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.BsqBlock;
import bisq.core.dao.blockchain.vo.Tx; 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.blockchain.vo.TxType;
import bisq.core.dao.node.BsqNode;
import bisq.core.dao.node.BsqNodeProvider;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -77,24 +74,23 @@ import javafx.collections.transformation.SortedList;
import javafx.util.Callback; import javafx.util.Callback;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@FxmlView @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 Pane rootParent;
private final BsqFormatter bsqFormatter; private final BsqFormatter bsqFormatter;
private final BsqWalletService bsqWalletService; private final BsqWalletService bsqWalletService;
private final ReadableBsqBlockChain readableBsqBlockChain; private final ReadableBsqBlockChain readableBsqBlockChain;
private final DaoPeriodService daoPeriodService;
private final BtcWalletService btcWalletService; private final BtcWalletService btcWalletService;
private final BsqBalanceUtil bsqBalanceUtil; private final BsqBalanceUtil bsqBalanceUtil;
private final BsqNode bsqNode;
private final Preferences preferences; private final Preferences preferences;
private final ObservableList<BsqTxListItem> observableList = FXCollections.observableArrayList(); private final ObservableList<BsqTxListItem> observableList = FXCollections.observableArrayList();
// Need to be DoubleProperty as we pass it as reference // 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 ListChangeListener<Transaction> walletBsqTransactionsListener;
private int gridRow = 0; private int gridRow = 0;
private Label chainHeightLabel; private Label chainHeightLabel;
private BsqNode.BsqBlockChainListener bsqBlockChainListener;
private ProgressBar chainSyncIndicator; private ProgressBar chainSyncIndicator;
private ChangeListener<Number> chainHeightChangedListener; private ChangeListener<Number> chainHeightChangedListener;
@ -116,18 +111,14 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
@Inject @Inject
private BsqTxView(BsqFormatter bsqFormatter, private BsqTxView(BsqFormatter bsqFormatter,
BsqWalletService bsqWalletService, BsqWalletService bsqWalletService,
BsqNodeProvider bsqNodeProvider,
Preferences preferences, Preferences preferences,
ReadableBsqBlockChain readableBsqBlockChain, ReadableBsqBlockChain readableBsqBlockChain,
DaoPeriodService daoPeriodService,
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
BsqBalanceUtil bsqBalanceUtil) { BsqBalanceUtil bsqBalanceUtil) {
this.bsqFormatter = bsqFormatter; this.bsqFormatter = bsqFormatter;
this.bsqWalletService = bsqWalletService; this.bsqWalletService = bsqWalletService;
this.bsqNode = bsqNodeProvider.getBsqNode();
this.preferences = preferences; this.preferences = preferences;
this.readableBsqBlockChain = readableBsqBlockChain; this.readableBsqBlockChain = readableBsqBlockChain;
this.daoPeriodService = daoPeriodService;
this.btcWalletService = btcWalletService; this.btcWalletService = btcWalletService;
this.bsqBalanceUtil = bsqBalanceUtil; this.bsqBalanceUtil = bsqBalanceUtil;
} }
@ -172,7 +163,6 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
walletBsqTransactionsListener = change -> updateList(); walletBsqTransactionsListener = change -> updateList();
parentHeightListener = (observable, oldValue, newValue) -> layout(); parentHeightListener = (observable, oldValue, newValue) -> layout();
bsqBlockChainListener = this::onChainHeightChanged;
chainHeightChangedListener = (observable, oldValue, newValue) -> onChainHeightChanged(); chainHeightChangedListener = (observable, oldValue, newValue) -> onChainHeightChanged();
} }
@ -186,7 +176,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
sortedList.comparatorProperty().bind(tableView.comparatorProperty()); sortedList.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(sortedList); tableView.setItems(sortedList);
bsqNode.addBsqBlockChainListener(bsqBlockChainListener); readableBsqBlockChain.addListener(this);
if (root.getParent() instanceof Pane) { if (root.getParent() instanceof Pane) {
rootParent = (Pane) root.getParent(); rootParent = (Pane) root.getParent();
@ -205,7 +195,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
bsqWalletService.getWalletTransactions().removeListener(walletBsqTransactionsListener); bsqWalletService.getWalletTransactions().removeListener(walletBsqTransactionsListener);
bsqWalletService.removeBsqBalanceListener(this); bsqWalletService.removeBsqBalanceListener(this);
btcWalletService.getChainHeightProperty().removeListener(chainHeightChangedListener); btcWalletService.getChainHeightProperty().removeListener(chainHeightChangedListener);
bsqNode.removeBsqBlockChainListener(bsqBlockChainListener); readableBsqBlockChain.removeListener(this);
observableList.forEach(BsqTxListItem::cleanup); observableList.forEach(BsqTxListItem::cleanup);
@ -213,6 +203,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
rootParent.heightProperty().removeListener(parentHeightListener); rootParent.heightProperty().removeListener(parentHeightListener);
} }
@Override @Override
public void onUpdateBalances(Coin confirmedBalance, public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance, Coin pendingBalance,
@ -221,6 +212,17 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
updateList(); updateList();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBlockChain.Listener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onBlockAdded(BsqBlock bsqBlock) {
onChainHeightChanged();
}
private void onChainHeightChanged() { private void onChainHeightChanged() {
final int bsqWalletChainHeight = bsqWalletService.getChainHeightProperty().get(); final int bsqWalletChainHeight = bsqWalletService.getChainHeightProperty().get();
final int bsqBlockChainHeight = readableBsqBlockChain.getChainHeadHeight(); final int bsqBlockChainHeight = readableBsqBlockChain.getChainHeadHeight();
@ -253,71 +255,18 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
// copy list to avoid ConcurrentModificationException // copy list to avoid ConcurrentModificationException
final List<Transaction> walletTransactions = new ArrayList<>(bsqWalletService.getWalletTransactions()); final List<Transaction> walletTransactions = new ArrayList<>(bsqWalletService.getWalletTransactions());
List<BsqTxListItem> items = walletTransactions.stream() List<BsqTxListItem> items = walletTransactions.stream()
.map(transaction -> new BsqTxListItem(transaction, .map(transaction -> {
bsqWalletService, final Optional<Tx> optionalTx = readableBsqBlockChain.getTx(transaction.getHashAsString());
btcWalletService, return new BsqTxListItem(transaction,
readableBsqBlockChain.getTxType(transaction.getHashAsString()), optionalTx,
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, bsqWalletService,
btcWalletService, btcWalletService,
Optional.of(TxType.ISSUANCE), readableBsqBlockChain.hasTxBurntFee(transaction.getHashAsString()),
item.isBurnedBsqTx(), transaction.getUpdateTime(),
new Date(blockTimeInSec * 1000),
bsqFormatter); bsqFormatter);
})
// On output 1 we have the issuance candidate .collect(Collectors.toList());
long issuanceValue = tx.getOutputs().get(1).getValue(); observableList.setAll(items);
issuanceItem.setAmount(Coin.valueOf(issuanceValue));
issuanceTxList.add(issuanceItem);
});
return issuanceTxList;
} }
private void layout() { private void layout() {
@ -353,7 +302,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
} }
}); });
tableView.getColumns().add(column); tableView.getColumns().add(column);
column.setComparator((o1, o2) -> o1.getDate().compareTo(o2.getDate())); column.setComparator(Comparator.comparing(BsqTxListItem::getDate));
column.setSortType(TableColumn.SortType.DESCENDING); column.setSortType(TableColumn.SortType.DESCENDING);
tableView.getSortOrder().add(column); 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) { public void updateItem(final BsqTxListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) { if (item != null && !empty) {
TxType txType = item.getTxType(); final TxType txType = item.getTxType();
String labelString = Res.get("dao.tx.type.enum." + txType.name()); String labelString = Res.get("dao.tx.type.enum." + txType.name());
Label label; Label label;
if (item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal()) { 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) if (field != null)
field.setOnAction(null); field.setOnAction(null);
@ -472,11 +429,12 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
@Override @Override
public void updateItem(final BsqTxListItem item, boolean empty) { public void updateItem(final BsqTxListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) if (item != null && !empty) {
setText(item.getConfirmations() > 0 && item.getTxType().ordinal() > TxType.INVALID.ordinal() ? TxType txType = item.getTxType();
setText(item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal() ?
bsqFormatter.formatCoin(item.getAmount()) : bsqFormatter.formatCoin(item.getAmount()) :
Res.get("shared.na")); Res.get("shared.na"));
else } else
setText(""); setText("");
} }
}; };
@ -570,8 +528,15 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
style = "dao-tx-type-default-icon"; style = "dao-tx-type-default-icon";
break; break;
case COMPENSATION_REQUEST: case COMPENSATION_REQUEST:
awesomeIcon = AwesomeIcon.FILE; if (item.getOptionalTx().isPresent() && item.getOptionalTx().get().isIssuanceTx()) {
style = "dao-tx-type-fee-icon"; 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; break;
case BLIND_VOTE: case BLIND_VOTE:
awesomeIcon = AwesomeIcon.THUMBS_UP; awesomeIcon = AwesomeIcon.THUMBS_UP;
@ -581,10 +546,6 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
awesomeIcon = AwesomeIcon.LIGHTBULB; awesomeIcon = AwesomeIcon.LIGHTBULB;
style = "dao-tx-type-vote-reveal-icon"; style = "dao-tx-type-vote-reveal-icon";
break; break;
case ISSUANCE:
awesomeIcon = AwesomeIcon.MONEY;
style = "dao-tx-type-issuance-icon";
break;
default: default:
awesomeIcon = AwesomeIcon.QUESTION_SIGN; awesomeIcon = AwesomeIcon.QUESTION_SIGN;
style = "dao-tx-type-unverified-icon"; 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.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.blockchain.BsqBlockChain; import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.trade.Tradable; import bisq.core.trade.Tradable;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -35,15 +35,15 @@ import javax.annotation.Nullable;
public class TransactionListItemFactory { public class TransactionListItemFactory {
private final BtcWalletService btcWalletService; private final BtcWalletService btcWalletService;
private final BsqWalletService bsqWalletService; private final BsqWalletService bsqWalletService;
private final BsqBlockChain bsqBlockChain; private final ReadableBsqBlockChain readableBsqBlockChain;
private final BSFormatter formatter; private final BSFormatter formatter;
@Inject @Inject
TransactionListItemFactory(BtcWalletService btcWalletService, BsqWalletService bsqWalletService, TransactionListItemFactory(BtcWalletService btcWalletService, BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain, BSFormatter formatter) { ReadableBsqBlockChain readableBsqBlockChain, BSFormatter formatter) {
this.btcWalletService = btcWalletService; this.btcWalletService = btcWalletService;
this.bsqWalletService = bsqWalletService; this.bsqWalletService = bsqWalletService;
this.bsqBlockChain = bsqBlockChain; this.readableBsqBlockChain = readableBsqBlockChain;
this.formatter = formatter; this.formatter = formatter;
} }
@ -51,6 +51,6 @@ public class TransactionListItemFactory {
Optional<Tradable> maybeTradable = Optional.ofNullable(tradable) Optional<Tradable> maybeTradable = Optional.ofNullable(tradable)
.map(TransactionAwareTradable::asTradable); .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.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletService; 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.dao.blockchain.vo.TxType;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
@ -80,7 +80,7 @@ class TransactionsListItem {
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
BsqWalletService bsqWalletService, BsqWalletService bsqWalletService,
Optional<Tradable> tradableOptional, Optional<Tradable> tradableOptional,
BsqBlockChain bsqBlockChain, ReadableBsqBlockChain readableBsqBlockChain,
BSFormatter formatter) { BSFormatter formatter) {
this.formatter = formatter; this.formatter = formatter;
txId = transaction.getHashAsString(); txId = transaction.getHashAsString();
@ -130,7 +130,7 @@ class TransactionsListItem {
txFeeForBsqPayment = true; 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)) if (txTypeOptional.isPresent() && txTypeOptional.get().equals(TxType.COMPENSATION_REQUEST))
details = Res.get("funds.tx.proposal"); details = Res.get("funds.tx.proposal");
} else { } else {

View file

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