diff --git a/src/main/java/bisq/desktop/app/BisqApp.java b/src/main/java/bisq/desktop/app/BisqApp.java index 59c8030845..331deeecd9 100644 --- a/src/main/java/bisq/desktop/app/BisqApp.java +++ b/src/main/java/bisq/desktop/app/BisqApp.java @@ -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 -> { diff --git a/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java b/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java index f366979067..4433be2fd9 100644 --- a/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java +++ b/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java @@ -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; diff --git a/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java b/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java index 7247ec2ea9..44474b4790 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java @@ -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 implements BsqNode.BsqBlockChainListener { +public abstract class BaseProposalView extends ActivatableView 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 proposalListItems = FXCollections.observableArrayList(); @@ -97,16 +96,14 @@ public abstract class BaseProposalView extends ActivatableView 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 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 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 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 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 i }; } }); - uidColumn.setComparator(Comparator.comparing(o -> o.getProposal().getProposalPayload().getUid())); + uidColumn.setComparator(Comparator.comparing(o -> o.getProposal().getUid())); tableView.getColumns().add(uidColumn); } diff --git a/src/main/java/bisq/desktop/main/dao/proposal/ProposalDetailsWindow.java b/src/main/java/bisq/desktop/main/dao/proposal/ProposalDetailsWindow.java index 0a43be7288..ab62952b14 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/ProposalDetailsWindow.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/ProposalDetailsWindow.java @@ -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; diff --git a/src/main/java/bisq/desktop/main/dao/proposal/ProposalDisplay.java b/src/main/java/bisq/desktop/main/dao/proposal/ProposalDisplay.java index 78e9c9d71b..7592dafcfa 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/ProposalDisplay.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/ProposalDisplay.java @@ -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 diff --git a/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java b/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java index 7614329684..bc664f00f9 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java @@ -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 chainHeightListener; private final ChangeListener 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); diff --git a/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java b/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java index e5dae4e6a2..79b5d09d15 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java @@ -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() { + blindVoteService.publishBlindVote(stake, new FutureCallback() { @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(); diff --git a/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java b/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java index d528133ee6..cf6e5d3d3c 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java @@ -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()); } } diff --git a/src/main/java/bisq/desktop/main/dao/proposal/dashboard/ProposalDashboardView.java b/src/main/java/bisq/desktop/main/dao/proposal/dashboard/ProposalDashboardView.java index 4625c649b4..861791ca75 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/dashboard/ProposalDashboardView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/dashboard/ProposalDashboardView.java @@ -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; diff --git a/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java b/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java index 150af069d4..00b4a5ac6b 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java @@ -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 { 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 { 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 { 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,33 +177,31 @@ public class MakeProposalView extends ActivatableView { 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() { - @Override - public void onSuccess(@Nullable Transaction transaction) { - proposalDisplay.clearForm(); + proposalService.publishProposal(proposal, + new FutureCallback() { + @Override + 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 - public void onFailure(@NotNull Throwable t) { - log.error(t.toString()); - new Popup<>().warning(t.toString()).show(); - } - }); + @Override + public void onFailure(@NotNull Throwable t) { + log.error(t.toString()); + new Popup<>().warning(t.toString()).show(); + } + }); }) .closeButtonText(Res.get("shared.cancel")) .show(); @@ -210,37 +209,45 @@ public class MakeProposalView extends ActivatableView { 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; diff --git a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java index dc04cd06de..5ac574a3bb 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java @@ -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 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 items = voteService.getMyVotesList().stream() - .map(vote -> new VoteListItem(vote, bsqWalletService, readableBsqBlockChain, bsqNodeProvider, bsqFormatter)) + List items = blindVoteService.getMyVotesList().stream() + .map(vote -> new VoteListItem(vote, bsqWalletService, readableBsqBlockChain, bsqFormatter)) .collect(Collectors.toList()); voteListItems.addAll(items); } diff --git a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java index 25a274563a..d822c8ea85 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java @@ -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) { diff --git a/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java b/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java index 67b057d5e9..a1dac3b057 100644 --- a/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java +++ b/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java @@ -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 implements BsqNode.BsqBlockChainListener { +public class BsqDashboardView extends ActivatableView 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 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 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 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)); diff --git a/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java b/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java index fe39e31d4d..21b2d9d7d8 100644 --- a/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java +++ b/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java @@ -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 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 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 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 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() { + walletsManager.publishAndCommitBsqTx(txWithBtcFee, new FutureCallback() { @Override public void onSuccess(@Nullable Transaction transaction) { if (transaction != null) { @@ -173,7 +172,7 @@ public class BsqSendView extends ActivatableView implements BsqB log.error(t.toString()); new Popup<>().warning(t.toString()); } - }, 15); + }); receiversAddressInputTextField.setText(""); amountInputTextField.setText(""); diff --git a/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxListItem.java b/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxListItem.java index c9d606e675..3734b33826 100644 --- a/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxListItem.java +++ b/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxListItem.java @@ -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 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 txTypeOptional; - @Getter private boolean isBurnedBsqTx; private BsqFormatter bsqFormatter; - @Getter private TxConfidenceIndicator txConfidenceIndicator; - private TxConfidenceListener txConfidenceListener; + private boolean issuanceTx; - public BsqTxListItem(Transaction transaction, - BsqWalletService bsqWalletService, - BtcWalletService btcWalletService, - Optional txTypeOptional, - boolean isBurnedBsqTx, - Date date, - BsqFormatter bsqFormatter) { + BsqTxListItem(Transaction transaction, + Optional optionalTx, + BsqWalletService bsqWalletService, + BtcWalletService btcWalletService, + 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; } diff --git a/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxView.java b/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxView.java index c12895c126..ae96f8a6a5 100644 --- a/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxView.java +++ b/src/main/java/bisq/desktop/main/dao/wallet/tx/BsqTxView.java @@ -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 implements BsqBalanceListener { +public class BsqTxView extends ActivatableView implements BsqBalanceListener, BsqBlockChain.Listener { - TableView tableView; + private TableView 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 observableList = FXCollections.observableArrayList(); // Need to be DoubleProperty as we pass it as reference @@ -104,7 +100,6 @@ public class BsqTxView extends ActivatableView implements BsqBal private ListChangeListener walletBsqTransactionsListener; private int gridRow = 0; private Label chainHeightLabel; - private BsqNode.BsqBlockChainListener bsqBlockChainListener; private ProgressBar chainSyncIndicator; private ChangeListener chainHeightChangedListener; @@ -116,18 +111,14 @@ public class BsqTxView extends ActivatableView 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 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 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 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 implements BsqBal rootParent.heightProperty().removeListener(parentHeightListener); } + @Override public void onUpdateBalances(Coin confirmedBalance, Coin pendingBalance, @@ -221,6 +212,17 @@ public class BsqTxView extends ActivatableView 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 implements BsqBal // copy list to avoid ConcurrentModificationException final List walletTransactions = new ArrayList<>(bsqWalletService.getWalletTransactions()); List items = walletTransactions.stream() - .map(transaction -> new BsqTxListItem(transaction, - 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 getCompensationRequestTxListItems(List items) { - List 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 optionalTx = readableBsqBlockChain.getTx(item.getTxId()); - if (optionalTx.isPresent()) { - final List 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(), + .map(transaction -> { + final Optional optionalTx = readableBsqBlockChain.getTx(transaction.getHashAsString()); + return new BsqTxListItem(transaction, + optionalTx, bsqWalletService, btcWalletService, - Optional.of(TxType.ISSUANCE), - item.isBurnedBsqTx(), - new Date(blockTimeInSec * 1000), + readableBsqBlockChain.hasTxBurntFee(transaction.getHashAsString()), + transaction.getUpdateTime(), 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 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 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 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 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 implements BsqBal style = "dao-tx-type-default-icon"; break; case COMPENSATION_REQUEST: - awesomeIcon = AwesomeIcon.FILE; - style = "dao-tx-type-fee-icon"; + 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 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"; diff --git a/src/main/java/bisq/desktop/main/funds/transactions/TransactionListItemFactory.java b/src/main/java/bisq/desktop/main/funds/transactions/TransactionListItemFactory.java index 33040fa751..b927b55aef 100644 --- a/src/main/java/bisq/desktop/main/funds/transactions/TransactionListItemFactory.java +++ b/src/main/java/bisq/desktop/main/funds/transactions/TransactionListItemFactory.java @@ -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 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); } } diff --git a/src/main/java/bisq/desktop/main/funds/transactions/TransactionsListItem.java b/src/main/java/bisq/desktop/main/funds/transactions/TransactionsListItem.java index e6c82afd1e..ef7f462365 100644 --- a/src/main/java/bisq/desktop/main/funds/transactions/TransactionsListItem.java +++ b/src/main/java/bisq/desktop/main/funds/transactions/TransactionsListItem.java @@ -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 tradableOptional, - BsqBlockChain bsqBlockChain, + ReadableBsqBlockChain readableBsqBlockChain, BSFormatter formatter) { this.formatter = formatter; txId = transaction.getHashAsString(); @@ -130,7 +130,7 @@ class TransactionsListItem { txFeeForBsqPayment = true; // - final Optional txTypeOptional = bsqBlockChain.getTxType(txId); + final Optional txTypeOptional = readableBsqBlockChain.getTxType(txId); if (txTypeOptional.isPresent() && txTypeOptional.get().equals(TxType.COMPENSATION_REQUEST)) details = Res.get("funds.tx.proposal"); } else { diff --git a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java index e50ecc9e8a..4a9971c097 100644 --- a/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java +++ b/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java @@ -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);