Skip to content

Commit

Permalink
Sign imported AccountAgeWitness,PubKey
Browse files Browse the repository at this point in the history
Change the specific sign window to sign an imported account in the form
of accountAgeWitnessString,pubKeyString. The SignSpecificWitness never
worked due to missing pubKey data and this is a way to import the missing data.
  • Loading branch information
sqrrm committed Dec 15, 2020
1 parent de25105 commit 4c33f9c
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import bisq.common.crypto.Sig;
import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.util.MathUtils;
import bisq.common.util.Tuple2;
import bisq.common.util.Utilities;

import org.bitcoinj.core.Coin;
Expand Down Expand Up @@ -886,4 +887,24 @@ public String signInfoFromAccount(PaymentAccount paymentAccount) {
var witness = getMyWitness(paymentAccount.getPaymentAccountPayload());
return Utilities.bytesAsHexString(witness.getHash()) + "," + Utilities.bytesAsHexString(pubKey.getEncoded());
}

public Tuple2<AccountAgeWitness, byte[]> signInfoFromString(String signInfo) {
var parts = signInfo.split(",");
if (parts.length != 2){
return null;
}
byte[] pubKeyHash;
Optional<AccountAgeWitness> accountAgeWitness;
try {
var accountAgeWitnessHash = Utilities.decodeFromHex(parts[0]);
pubKeyHash = Utilities.decodeFromHex(parts[1]);
accountAgeWitness = getWitnessByHash(accountAgeWitnessHash);
} catch (Exception e) {
return null;
}

return accountAgeWitness
.map(ageWitness -> new Tuple2<>(ageWitness, pubKeyHash))
.orElse(null);
}
}
5 changes: 1 addition & 4 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2892,15 +2892,12 @@ popup.accountSigning.peerLimitLifted=The initial limit for one of your accounts
popup.accountSigning.peerSigner=One of your accounts is mature enough to sign other payment accounts \
and the initial limit for one of your accounts has been lifted.\n\n{0}

popup.accountSigning.singleAccountSelect.headline=Select account age witness
popup.accountSigning.singleAccountSelect.description=Search for account age witness.
popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing
popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness
popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness
popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash
popup.accountSigning.confirmSingleAccount.button=Sign account age witness
popup.accountSigning.successSingleAccount.description=Witness {0} was signed
popup.accountSigning.successSingleAccount.success.headline=Success
popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0}

popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys
popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package bisq.desktop.main.overlays.windows;

import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.BisqTextArea;
import bisq.desktop.components.InputTextField;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.main.overlays.popups.Popup;
Expand All @@ -27,24 +28,21 @@
import bisq.core.locale.Res;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;

import bisq.common.util.Tuple2;
import bisq.common.util.Utilities;

import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Utils;

import javax.inject.Inject;

import com.jfoenix.controls.JFXAutoCompletePopup;

import javafx.scene.control.DatePicker;
import javafx.scene.control.ListCell;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;

import javafx.geometry.VPos;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;

import lombok.extern.slf4j.Slf4j;

Expand All @@ -53,10 +51,7 @@
@Slf4j
public class SignSpecificWitnessWindow extends Overlay<SignSpecificWitnessWindow> {

private InputTextField searchTextField;
private JFXAutoCompletePopup<AccountAgeWitness> searchAutoComplete;
private AccountAgeWitness selectedWitness;
private DatePicker datePicker;
private Tuple2<AccountAgeWitness, byte[]> signInfo;
private InputTextField privateKey;
private final AccountAgeWitnessService accountAgeWitnessService;
private final ArbitratorManager arbitratorManager;
Expand Down Expand Up @@ -89,103 +84,75 @@ public void show() {
}

private void addSelectWitnessContent() {
searchTextField = addInputTextField(gridPane, ++rowIndex,
Res.get("popup.accountSigning.singleAccountSelect.description"));

searchAutoComplete = new JFXAutoCompletePopup<>();
searchAutoComplete.setPrefWidth(400);
searchAutoComplete.getSuggestions().addAll(accountAgeWitnessService.getOrphanSignedWitnesses());
searchAutoComplete.setSuggestionsCellFactory(param -> new ListCell<>() {
@Override
protected void updateItem(AccountAgeWitness item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(Utilities.bytesAsHexString(item.getHash()));
} else {
setText("");
}
TextArea accountInfoText = new BisqTextArea();
accountInfoText.setPrefHeight(270);
accountInfoText.setWrapText(true);
GridPane.setRowIndex(accountInfoText, ++rowIndex);
gridPane.getChildren().add(accountInfoText);

accountInfoText.textProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == null || newValue.isEmpty()) {
return;
}
});
searchAutoComplete.setSelectionHandler(event -> {
searchTextField.setText(Utilities.bytesAsHexString(event.getObject().getHash()));
selectedWitness = event.getObject();
if (selectedWitness != null) {
datePicker.setValue(Instant.ofEpochMilli(selectedWitness.getDate()).atZone(
ZoneId.systemDefault()).toLocalDate());
signInfo = accountAgeWitnessService.signInfoFromString(newValue);
if (signInfo == null) {
actionButton.setDisable(true);
return;
}
actionButton.setDisable(false);
});

searchTextField.textProperty().addListener(observable -> {
searchAutoComplete.filter(witness -> Utilities.bytesAsHexString(witness.getHash()).startsWith(
searchTextField.getText().toLowerCase()));
if (searchAutoComplete.getFilteredSuggestions().isEmpty()) {
searchAutoComplete.hide();
} else {
searchAutoComplete.show(searchTextField);
}
});

datePicker = addTopLabelDatePicker(gridPane, ++rowIndex,
Res.get("popup.accountSigning.singleAccountSelect.datePicker"),
0).second;
datePicker.setOnAction(e -> updateWitnessSelectionState());
}

private void addECKeyField() {
privateKey = addInputTextField(gridPane, ++rowIndex, Res.get("popup.accountSigning.signAccounts.ECKey"));
actionButton.setDisable(true);
GridPane.setVgrow(privateKey, Priority.ALWAYS);
GridPane.setValignment(privateKey, VPos.TOP);
}

private void updateWitnessSelectionState() {
actionButton.setDisable(selectedWitness == null || datePicker.getValue() == null);
privateKey.textProperty().addListener((observable, oldValue, newValue) -> {
if (checkedArbitratorKey() == null) {
actionButton.setDisable(true);
return;
}
actionButton.setDisable(false);
});
}

private void removeContent() {
removeRowsFromGridPane(gridPane, 1, 3);
rowIndex = 1;
}

private void selectAccountAgeWitness() {
private void importAccountAgeWitness() {
removeContent();
headLineLabel.setText(Res.get("popup.accountSigning.confirmSingleAccount.headline"));
var selectedWitnessTextField = addTopLabelTextField(gridPane, ++rowIndex,
Res.get("popup.accountSigning.confirmSingleAccount.selectedHash")).second;
selectedWitnessTextField.setText(Utilities.bytesAsHexString(selectedWitness.getHash()));
selectedWitnessTextField.setText(Utilities.bytesAsHexString(signInfo.first.getHash()));
addECKeyField();
((AutoTooltipButton) actionButton).updateText(Res.get("popup.accountSigning.confirmSingleAccount.button"));
actionButton.setOnAction(a -> {
var arbitratorKey = arbitratorManager.getRegistrationKey(privateKey.getText());
var arbitratorKey = checkedArbitratorKey();
if (arbitratorKey != null) {
var arbitratorPubKeyAsHex = Utils.HEX.encode(arbitratorKey.getPubKey());
var isKeyValid = arbitratorManager.isPublicKeyInList(arbitratorPubKeyAsHex);
if (isKeyValid) {
var result = accountAgeWitnessService.arbitratorSignOrphanWitness(selectedWitness,
arbitratorKey,
datePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000);
if (result.isEmpty()) {
addSuccessContent();
} else {
new Popup().error(Res.get("popup.accountSigning.successSingleAccount.signError", result))
.onClose(this::hide).show();
}
}
accountAgeWitnessService.arbitratorSignAccountAgeWitness(signInfo.first,
arbitratorKey,
signInfo.second,
new Date().getTime());
addSuccessContent();
} else {
new Popup().error(Res.get("popup.accountSigning.signAccounts.ECKey.error")).onClose(this::hide).show();
}

});
}


private void addSuccessContent() {
removeContent();
closeButton.setVisible(false);
closeButton.setManaged(false);
headLineLabel.setText(Res.get("popup.accountSigning.successSingleAccount.success.headline"));
var descriptionLabel = addMultilineLabel(gridPane, ++rowIndex,
Res.get("popup.accountSigning.successSingleAccount.description",
Utilities.bytesAsHexString(selectedWitness.getHash())));
Utilities.bytesAsHexString(signInfo.first.getHash())));
GridPane.setVgrow(descriptionLabel, Priority.ALWAYS);
GridPane.setValignment(descriptionLabel, VPos.TOP);
((AutoTooltipButton) actionButton).updateText(Res.get("shared.ok"));
Expand All @@ -194,15 +161,24 @@ private void addSuccessContent() {

@Override
protected void addButtons() {
var buttonTuple = add2ButtonsAfterGroup(gridPane, ++rowIndex + 1,
var buttonTuple = add2ButtonsAfterGroup(gridPane, ++rowIndex + 2,
Res.get("popup.accountSigning.singleAccountSelect.headline"), Res.get("shared.cancel"));

actionButton = buttonTuple.first;
actionButton.setDisable(true);
actionButton.setOnAction(e -> selectAccountAgeWitness());
actionButton.setOnAction(e -> importAccountAgeWitness());

closeButton = (AutoTooltipButton) buttonTuple.second;
closeButton.setOnAction(e -> hide());
}

private ECKey checkedArbitratorKey() {
var arbitratorKey = arbitratorManager.getRegistrationKey(privateKey.getText());
if (arbitratorKey == null) {
return null;
}
var arbitratorPubKeyAsHex = Utils.HEX.encode(arbitratorKey.getPubKey());
var isKeyValid = arbitratorManager.isPublicKeyInList(arbitratorPubKeyAsHex);
return isKeyValid ? arbitratorKey : null;
}
}

0 comments on commit 4c33f9c

Please sign in to comment.