Create data structures and tx for blind voting

This commit is contained in:
Manfred Karrer 2018-03-20 23:03:58 -05:00
parent 443abc0ec6
commit 11deab6453
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
6 changed files with 119 additions and 63 deletions

View file

@ -31,7 +31,7 @@ import bisq.core.dao.blockchain.BsqBlockChain;
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
import bisq.core.dao.blockchain.BsqBlockChainListener;
import bisq.core.dao.proposal.Proposal;
import bisq.core.dao.proposal.ProposalCollectionsManager;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.proposal.ProposalPayload;
import bisq.core.locale.Res;
@ -67,7 +67,7 @@ import java.util.stream.Collectors;
@FxmlView
public abstract class BaseProposalView extends ActivatableView<GridPane, Void> implements BsqBlockChainListener {
protected final ProposalCollectionsManager proposalCollectionsManager;
protected final ProposalCollectionsService proposalCollectionsService;
protected final BsqBlockChain bsqBlockChain;
protected final ObservableList<ProposalListItem> proposalListItems = FXCollections.observableArrayList();
protected TableView<ProposalListItem> tableView;
@ -92,13 +92,13 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
protected BaseProposalView(ProposalCollectionsManager proposalCollectionsManager,
protected BaseProposalView(ProposalCollectionsService proposalCollectionsService,
BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
DaoPeriodService daoPeriodService,
BsqFormatter bsqFormatter) {
this.proposalCollectionsManager = proposalCollectionsManager;
this.proposalCollectionsService = proposalCollectionsService;
this.bsqWalletService = bsqWalletService;
this.bsqBlockChain = bsqBlockChain;
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
@ -165,7 +165,7 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
selectedProposalSubscription = EasyBind.subscribe(tableView.getSelectionModel().selectedItemProperty(), this::onSelectProposal);
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
proposalCollectionsManager.getAllProposals().addListener(proposalListChangeListener);
proposalCollectionsService.getAllProposals().addListener(proposalListChangeListener);
updateList();
}
@ -179,7 +179,7 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
selectedProposalSubscription.unsubscribe();
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
proposalCollectionsManager.getAllProposals().removeListener(proposalListChangeListener);
proposalCollectionsService.getAllProposals().removeListener(proposalListChangeListener);
proposalListItems.forEach(ProposalListItem::cleanup);
@ -213,7 +213,7 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
proposalListItems.setAll(list.stream()
.map(proposal -> new ProposalListItem(proposal,
proposalCollectionsManager,
proposalCollectionsService,
daoPeriodService,
bsqWalletService,
bsqBlockChain,

View file

@ -32,7 +32,7 @@ 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.ProposalRestrictions;
import bisq.core.dao.proposal.consensus.ProposalConsensus;
import bisq.core.locale.Res;
import bisq.core.provider.fee.FeeService;
@ -80,10 +80,10 @@ public class ProposalDisplay {
this.bsqWalletService = bsqWalletService;
this.feeService = feeService;
maxLengthDescriptionText = ProposalRestrictions.getMaxLengthDescriptionText();
maxLengthDescriptionText = ProposalConsensus.getMaxLengthDescriptionText();
descriptionTextAreaListener = (observable, oldValue, newValue) -> {
if (!ProposalRestrictions.isDescriptionSizeValid(newValue)) {
if (!ProposalConsensus.isDescriptionSizeValid(newValue)) {
new Popup<>().warning(Res.get("dao.proposal.display.description.tooLong", maxLengthDescriptionText)).show();
descriptionTextArea.setText(newValue.substring(0, maxLengthDescriptionText));
}

View file

@ -29,7 +29,7 @@ import bisq.core.dao.blockchain.BsqBlockChainListener;
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
import bisq.core.dao.blockchain.vo.Tx;
import bisq.core.dao.proposal.Proposal;
import bisq.core.dao.proposal.ProposalCollectionsManager;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.vote.BooleanVoteResult;
import bisq.core.dao.vote.VoteResult;
import bisq.core.locale.Res;
@ -57,7 +57,7 @@ import lombok.extern.slf4j.Slf4j;
public class ProposalListItem implements BsqBlockChainListener {
@Getter
private final Proposal proposal;
private final ProposalCollectionsManager proposalCollectionsManager;
private final ProposalCollectionsService proposalCollectionsService;
private final DaoPeriodService daoPeriodService;
private final BsqWalletService bsqWalletService;
private final ReadableBsqBlockChain readableBsqBlockChain;
@ -81,14 +81,14 @@ public class ProposalListItem implements BsqBlockChainListener {
private Node actionNode;
ProposalListItem(Proposal proposal,
ProposalCollectionsManager proposalCollectionsManager,
ProposalCollectionsService proposalCollectionsService,
DaoPeriodService daoPeriodService,
BsqWalletService bsqWalletService,
ReadableBsqBlockChain readableBsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
BsqFormatter bsqFormatter) {
this.proposal = proposal;
this.proposalCollectionsManager = proposalCollectionsManager;
this.proposalCollectionsService = proposalCollectionsService;
this.daoPeriodService = daoPeriodService;
this.bsqWalletService = bsqWalletService;
this.readableBsqBlockChain = readableBsqBlockChain;
@ -130,13 +130,13 @@ public class ProposalListItem implements BsqBlockChainListener {
actionButton.setText("");
actionButton.setVisible(false);
actionButton.setOnAction(null);
final boolean isTxInPastCycle = daoPeriodService.isTxInPastCycle(proposal.getTxId());
switch (newValue) {
case UNDEFINED:
break;
case PROPOSAL:
if (proposalCollectionsManager.isMine(proposal)) {
actionButton.setVisible(!proposal.isClosed());
if (proposalCollectionsService.isMine(proposal)) {
actionButton.setVisible(!isTxInPastCycle);
actionButtonIconView.setVisible(actionButton.isVisible());
actionButton.setText(Res.get("shared.remove"));
actionButton.setGraphic(actionButtonIconView);
@ -148,7 +148,7 @@ public class ProposalListItem implements BsqBlockChainListener {
case BREAK1:
break;
case OPEN_FOR_VOTING:
if (!proposal.isClosed()) {
if (!isTxInPastCycle) {
actionNode = actionButtonIconView;
actionButton.setVisible(false);
if (proposal.getVoteResult() != null) {

View file

@ -25,21 +25,32 @@ import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.BsqFormatter;
import bisq.desktop.util.Layout;
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.ProposalCollectionsManager;
import bisq.core.dao.proposal.ProposalCollectionsService;
import bisq.core.dao.vote.BooleanVoteResult;
import bisq.core.dao.vote.VoteManager;
import bisq.core.dao.vote.VoteService;
import bisq.core.locale.Res;
import bisq.common.crypto.CryptoException;
import bisq.common.util.Tuple3;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import javax.inject.Inject;
import com.google.common.util.concurrent.FutureCallback;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
@ -52,6 +63,8 @@ import javafx.util.Callback;
import java.util.Comparator;
import javax.annotation.Nullable;
import static bisq.desktop.util.FormBuilder.add3ButtonsAfterGroup;
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
import static bisq.desktop.util.FormBuilder.addLabelInputTextField;
@ -60,7 +73,7 @@ import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
@FxmlView
public class ActiveProposalsView extends BaseProposalView {
private final VoteManager voteManager;
private final VoteService voteService;
private Button removeButton, acceptButton, rejectButton, cancelVoteButton, voteButton;
private InputTextField stakeInputTextField;
@ -71,16 +84,16 @@ public class ActiveProposalsView extends BaseProposalView {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private ActiveProposalsView(ProposalCollectionsManager voteRequestManger,
private ActiveProposalsView(ProposalCollectionsService voteRequestManger,
DaoPeriodService daoPeriodService,
VoteManager voteManager,
VoteService voteService,
BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
BsqFormatter bsqFormatter) {
super(voteRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
bsqFormatter);
this.voteManager = voteManager;
this.voteService = voteService;
}
@Override
@ -108,7 +121,35 @@ public class ActiveProposalsView extends BaseProposalView {
(bsqWalletService.getAvailableBalance())));
voteButton.setOnAction(e -> {
voteManager.vote();
Coin stake = bsqFormatter.parseToCoin(stakeInputTextField.getText());
// TODO verify stake
//TODO show popup
try {
voteService.publishBlindVote(stake, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction result) {
//TODO
}
@Override
public void onFailure(Throwable t) {
//TODO
}
});
} catch (CryptoException e1) {
//TODO show error popup
e1.printStackTrace();
} catch (InsufficientBsqException e1) {
e1.printStackTrace();
} catch (WalletException e1) {
e1.printStackTrace();
} catch (TransactionVerificationException e1) {
e1.printStackTrace();
} catch (InsufficientMoneyException e1) {
e1.printStackTrace();
} catch (ChangeBelowDustException e1) {
e1.printStackTrace();
}
});
}
@ -122,7 +163,7 @@ public class ActiveProposalsView extends BaseProposalView {
@Override
protected void updateList() {
doUpdateList(proposalCollectionsManager.getActiveProposals());
doUpdateList(proposalCollectionsService.getActiveProposals());
}
protected void onSelectProposal(ProposalListItem item) {
@ -170,12 +211,12 @@ public class ActiveProposalsView extends BaseProposalView {
private void updateStateAfterVote() {
removeProposalDisplay();
proposalCollectionsManager.queueUpForSave();
proposalCollectionsService.queueUpForSave();
tableView.getSelectionModel().clearSelection();
}
private void onRemove() {
if (proposalCollectionsManager.removeProposal(selectedProposalListItem.getProposal()))
if (proposalCollectionsService.removeProposal(selectedProposalListItem.getProposal()))
removeProposalDisplay();
else
new Popup<>().warning(Res.get("dao.proposal.active.remove.failed")).show();
@ -190,11 +231,13 @@ public class ActiveProposalsView extends BaseProposalView {
removeButton.setVisible(false);
removeButton = null;
}
if (selectedProposalListItem != null && proposalDisplay != null && !selectedProposalListItem.getProposal().isClosed()) {
if (selectedProposalListItem != null &&
proposalDisplay != null &&
!daoPeriodService.isTxInPastCycle(selectedProposalListItem.getProposal().getTxId())) {
final Proposal proposal = selectedProposalListItem.getProposal();
switch (phase) {
case PROPOSAL:
if (proposalCollectionsManager.isMine(proposal)) {
if (proposalCollectionsService.isMine(proposal)) {
if (removeButton == null) {
removeButton = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.active.remove"));
removeButton.setOnAction(event -> onRemove());

View file

@ -25,7 +25,7 @@ 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.ProposalCollectionsManager;
import bisq.core.dao.proposal.ProposalCollectionsService;
import javax.inject.Inject;
@ -37,13 +37,13 @@ public class ClosedProposalsView extends BaseProposalView {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private ClosedProposalsView(ProposalCollectionsManager proposalCollectionsManager,
private ClosedProposalsView(ProposalCollectionsService proposalCollectionsService,
DaoPeriodService daoPeriodService,
BsqWalletService bsqWalletService,
BsqBlockChain bsqBlockChain,
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
BsqFormatter bsqFormatter) {
super(proposalCollectionsManager, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
super(proposalCollectionsService, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
bsqFormatter);
}
@ -68,7 +68,7 @@ public class ClosedProposalsView extends BaseProposalView {
@Override
protected void updateList() {
doUpdateList(proposalCollectionsManager.getClosedProposals());
doUpdateList(proposalCollectionsService.getClosedProposals());
}
}

View file

@ -29,17 +29,19 @@ 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.ProposalCollectionsManager;
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.CompensationRequestManager;
import bisq.core.dao.proposal.compensation.CompensationRequestPayload;
import bisq.core.dao.proposal.consensus.ProposalRestrictions;
import bisq.core.dao.proposal.generic.GenericProposalManager;
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.locale.Res;
import bisq.core.provider.fee.FeeService;
import bisq.core.util.CoinUtil;
@ -88,9 +90,10 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
private final WalletsSetup walletsSetup;
private final P2PService p2PService;
private final FeeService feeService;
private final ProposalCollectionsManager proposalCollectionsManager;
private final CompensationRequestManager compensationRequestManager;
private final GenericProposalManager genericProposalManager;
private final ProposalCollectionsService proposalCollectionsService;
private final CompensationRequestService compensationRequestService;
private final GenericProposalService genericProposalService;
private final ReadableBsqBlockChain readableBsqBlockChain;
private final BSFormatter btcFormatter;
private final BsqFormatter bsqFormatter;
private ComboBox<ProposalType> proposalTypeComboBox;
@ -107,18 +110,20 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
WalletsSetup walletsSetup,
P2PService p2PService,
FeeService feeService,
ProposalCollectionsManager proposalCollectionsManager,
CompensationRequestManager compensationRequestManager,
GenericProposalManager genericProposalManager,
ProposalCollectionsService proposalCollectionsService,
CompensationRequestService compensationRequestService,
GenericProposalService genericProposalService,
ReadableBsqBlockChain readableBsqBlockChain,
BSFormatter btcFormatter,
BsqFormatter bsqFormatter) {
this.bsqWalletService = bsqWalletService;
this.walletsSetup = walletsSetup;
this.p2PService = p2PService;
this.feeService = feeService;
this.proposalCollectionsManager = proposalCollectionsManager;
this.compensationRequestManager = compensationRequestManager;
this.genericProposalManager = genericProposalManager;
this.proposalCollectionsService = proposalCollectionsService;
this.compensationRequestService = compensationRequestService;
this.genericProposalService = genericProposalService;
this.readableBsqBlockChain = readableBsqBlockChain;
this.btcFormatter = btcFormatter;
this.bsqFormatter = bsqFormatter;
}
@ -127,7 +132,8 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
@Override
public void initialize() {
addTitledGroupBg(root, 0, 1, Res.get("dao.proposal.create.selectProposalType"));
proposalTypeComboBox = addLabelComboBox(root, 0, Res.getWithCol("dao.proposal.create.proposalType"), Layout.FIRST_ROW_DISTANCE).second;
proposalTypeComboBox = addLabelComboBox(root, 0,
Res.getWithCol("dao.proposal.create.proposalType"), Layout.FIRST_ROW_DISTANCE).second;
proposalTypeComboBox.setConverter(new StringConverter<ProposalType>() {
@Override
public String toString(ProposalType object) {
@ -163,23 +169,25 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
createButton.setOnAction(null);
}
private void createCompensationRequest(ProposalType type) {
private void publishProposal(ProposalType type) {
try {
Proposal proposal = createProposal(type);
Coin miningFee = Objects.requireNonNull(proposal).getTx().getFee();
int txSize = proposal.getTx().bitcoinSerialize().length;
Transaction tx = Objects.requireNonNull(proposal).getTx();
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(proposal.getFeeAsCoin()),
bsqFormatter.formatCoinWithCode(
ProposalConsensus.getCreateCompensationRequestFee(readableBsqBlockChain)),
btcFormatter.formatCoinWithCode(miningFee),
CoinUtil.getFeePerByte(miningFee, txSize),
(txSize / 1000d)))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> {
proposalCollectionsManager.publishProposal(proposal, new FutureCallback<Transaction>() {
proposalCollectionsService.publishProposal(proposal, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction transaction) {
proposalDisplay.clearForm();
@ -200,34 +208,39 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
.show();
} catch (InsufficientMoneyException e) {
BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter;
new Popup<>().warning(Res.get("dao.proposal.create.missingFunds", formatter.formatCoinWithCode(e.missing))).show();
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();
new Popup<>().warning(Res.get("validation.bsq.amountBelowMinAmount",
bsqFormatter.formatCoinWithCode(e.required))).show();
} catch (TransactionVerificationException | WalletException 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 {
private Proposal createProposal(ProposalType type) throws InsufficientMoneyException, TransactionVerificationException, CompensationAmountException, WalletException, ChangeBelowDustException {
switch (type) {
case COMPENSATION_REQUEST:
CompensationRequestPayload compensationRequestPayload = compensationRequestManager.getNewCompensationRequestPayload(
CompensationRequestPayload compensationRequestPayload = compensationRequestService.getNewCompensationRequestPayload(
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 compensationRequestManager.prepareCompensationRequest(compensationRequestPayload);
return compensationRequestService.prepareCompensationRequest(compensationRequestPayload);
case GENERIC:
GenericProposalPayload genericProposalPayload = genericProposalManager.getNewGenericProposalPayload(
GenericProposalPayload genericProposalPayload = genericProposalService.getNewGenericProposalPayload(
proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText());
return genericProposalManager.prepareGenericProposal(genericProposalPayload);
return genericProposalService.prepareGenericProposal(genericProposalPayload);
case CHANGE_PARAM:
//TODO
return null;
@ -264,7 +277,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
createButton.setOnAction(event -> {
// TODO break up in methods
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
createCompensationRequest(selectedProposalType);
publishProposal(selectedProposalType);
} else {
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
}
@ -273,8 +286,8 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> {
private void validateInputs() {
// We check in proposalDisplay that no invalid input as allowed
checkArgument(ProposalRestrictions.isDescriptionSizeValid(proposalDisplay.descriptionTextArea.getText()), "descriptionText must not be longer than " +
ProposalRestrictions.getMaxLengthDescriptionText() + " chars");
checkArgument(ProposalConsensus.isDescriptionSizeValid(proposalDisplay.descriptionTextArea.getText()), "descriptionText must not be longer than " +
ProposalConsensus.getMaxLengthDescriptionText() + " chars");
// TODO add more checks for all input fields
}