register arbitrator from api and use throughout trade

This commit is contained in:
woodser 2022-04-26 19:55:48 -04:00
parent c2f5adac9b
commit 716f62797d
15 changed files with 99 additions and 39 deletions

View file

@ -17,7 +17,11 @@
package bisq.core.api;
import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.support.SupportType;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
import bisq.core.support.dispute.refund.refundagent.RefundAgent;
@ -33,7 +37,7 @@ import org.bitcoinj.core.ECKey;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@ -57,6 +61,8 @@ class CoreDisputeAgentsService {
private final User user;
private final Config config;
private final KeyRing keyRing;
private final BtcWalletService btcWalletService;
private final ArbitratorManager arbitratorManager;
private final MediatorManager mediatorManager;
private final RefundAgentManager refundAgentManager;
private final P2PService p2PService;
@ -67,12 +73,16 @@ class CoreDisputeAgentsService {
public CoreDisputeAgentsService(User user,
Config config,
KeyRing keyRing,
BtcWalletService btcWalletService,
ArbitratorManager arbitratorManager,
MediatorManager mediatorManager,
RefundAgentManager refundAgentManager,
P2PService p2PService) {
this.user = user;
this.config = config;
this.keyRing = keyRing;
this.btcWalletService = btcWalletService;
this.arbitratorManager = arbitratorManager;
this.mediatorManager = mediatorManager;
this.refundAgentManager = refundAgentManager;
this.p2PService = p2PService;
@ -97,7 +107,14 @@ class CoreDisputeAgentsService {
String signature;
switch (supportType.get()) {
case ARBITRATION:
throw new IllegalArgumentException("arbitrators must be registered in a Bisq UI");
if (user.getRegisteredArbitrator() != null) {
log.warn("ignoring request to re-register as arbitrator");
return;
}
ecKey = arbitratorManager.getRegistrationKey(registrationKey);
signature = arbitratorManager.signStorageSignaturePubKey(Objects.requireNonNull(ecKey));
registerArbitrator(nodeAddress, languageCodes, ecKey, signature);
return;
case MEDIATION:
if (user.getRegisteredMediator() != null) {
log.warn("ignoring request to re-register as mediator");
@ -124,6 +141,30 @@ class CoreDisputeAgentsService {
}
}
private void registerArbitrator(NodeAddress nodeAddress,
List<String> languageCodes,
ECKey ecKey,
String signature) {
AddressEntry arbitratorAddressEntry = btcWalletService.getArbitratorAddressEntry(); // TODO (woodser): switch to XMR; no reason for arbitrator to have BTC address / pub key
Arbitrator arbitrator = new Arbitrator(
p2PService.getAddress(),
arbitratorAddressEntry.getPubKey(),
arbitratorAddressEntry.getAddressString(),
keyRing.getPubKeyRing(),
new ArrayList<>(languageCodes),
new Date().getTime(),
ecKey.getPubKey(),
signature,
"",
null,
null);
arbitratorManager.addDisputeAgent(arbitrator, () -> {
}, errorMessage -> {
});
arbitratorManager.getDisputeAgentByNodeAddress(nodeAddress).orElseThrow(() ->
new IllegalStateException("could not register arbitrator"));
}
private void registerMediator(NodeAddress nodeAddress,
List<String> languageCodes,
ECKey ecKey,

View file

@ -637,6 +637,14 @@ public class XmrWalletService {
}
}
public XmrAddressEntry getArbitratorAddressEntry() {
XmrAddressEntry.Context context = XmrAddressEntry.Context.ARBITRATOR;
Optional<XmrAddressEntry> addressEntry = getAddressEntryListAsImmutableList().stream()
.filter(e -> context == e.getContext())
.findAny();
return getOrCreateAddressEntry(context, addressEntry);
}
public Optional<XmrAddressEntry> getAddressEntry(String offerId, XmrAddressEntry.Context context) {
return getAddressEntryListAsImmutableList().stream().filter(e -> offerId.equals(e.getOfferId())).filter(e -> context == e.getContext()).findAny();
}
@ -672,6 +680,19 @@ public class XmrWalletService {
swapTradeEntryToAvailableEntry(offerId, XmrAddressEntry.Context.TRADE_PAYOUT);
}
private XmrAddressEntry getOrCreateAddressEntry(XmrAddressEntry.Context context,
Optional<XmrAddressEntry> addressEntry) {
if (addressEntry.isPresent()) {
return addressEntry.get();
} else {
MoneroSubaddress subaddress = wallet.createSubaddress(0);
XmrAddressEntry entry = new XmrAddressEntry(subaddress.getIndex(), subaddress.getAddress(), context, null, null);
log.info("getOrCreateAddressEntry: add new XmrAddressEntry {}", entry);
xmrAddressEntryList.addAddressEntry(entry);
return entry;
}
}
private Optional<XmrAddressEntry> findAddressEntry(String address, XmrAddressEntry.Context context) {
return getAddressEntryListAsImmutableList().stream().filter(e -> address.equals(e.getAddressString())).filter(e -> context == e.getContext()).findAny();
}

View file

@ -28,8 +28,8 @@ import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.core.user.Preferences;
import bisq.core.user.User;
@ -69,7 +69,7 @@ public class CreateOfferService {
private final User user;
private final BtcWalletService btcWalletService;
private final TradeStatisticsManager tradeStatisticsManager;
private final MediatorManager mediatorManager;
private final ArbitratorManager arbitratorManager;
///////////////////////////////////////////////////////////////////////////////////////////
@ -85,7 +85,7 @@ public class CreateOfferService {
User user,
BtcWalletService btcWalletService,
TradeStatisticsManager tradeStatisticsManager,
MediatorManager mediatorManager) {
ArbitratorManager arbitratorManager) {
this.offerUtil = offerUtil;
this.txFeeEstimationService = txFeeEstimationService;
this.priceFeedService = priceFeedService;
@ -94,7 +94,7 @@ public class CreateOfferService {
this.user = user;
this.btcWalletService = btcWalletService;
this.tradeStatisticsManager = tradeStatisticsManager;
this.mediatorManager = mediatorManager;
this.arbitratorManager = arbitratorManager;
}
@ -192,7 +192,7 @@ public class CreateOfferService {
makerFeeAsCoin);
// select signing arbitrator
Mediator arbitrator = DisputeAgentSelection.getLeastUsedArbitrator(tradeStatisticsManager, mediatorManager); // TODO (woodser): using mediator manager for arbitrators
Arbitrator arbitrator = DisputeAgentSelection.getLeastUsedArbitrator(tradeStatisticsManager, arbitratorManager);
OfferPayload offerPayload = new OfferPayload(offerId,
creationTime,
@ -214,7 +214,7 @@ public class CreateOfferService {
bankId,
acceptedBanks,
Version.VERSION,
btcWalletService.getLastBlockSeenHeight(),
btcWalletService.getLastBlockSeenHeight(), // TODO (woodser): switch to XMR
txFeeToUse.value,
makerFeeAsCoin.value,
buyerSecurityDepositAsCoin.value,

View file

@ -22,7 +22,7 @@ import bisq.core.filter.FilterManager;
import bisq.core.locale.CurrencyUtil;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.trade.TradeUtils;
import bisq.core.user.Preferences;
import bisq.core.user.User;
@ -216,7 +216,7 @@ public class OfferFilter {
public boolean hasValidSignature(Offer offer) {
// get arbitrator
Mediator arbitrator = user.getAcceptedMediatorByAddress(offer.getOfferPayload().getArbitratorSigner());
Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(offer.getOfferPayload().getArbitratorSigner());
if (arbitrator == null) return false; // invalid arbitrator
// validate arbitrator signature

View file

@ -33,11 +33,11 @@ import bisq.core.offer.messages.SignOfferResponse;
import bisq.core.offer.placeoffer.PlaceOfferModel;
import bisq.core.offer.placeoffer.PlaceOfferProtocol;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
import bisq.core.trade.TradableList;
import bisq.core.trade.TradeUtils;
import bisq.core.trade.closed.ClosedTradableManager;
import bisq.core.trade.handlers.TransactionResultHandler;
import bisq.core.trade.statistics.TradeStatisticsManager;
@ -634,7 +634,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
try {
// verify this node is an arbitrator
Mediator thisArbitrator = user.getRegisteredMediator();
Arbitrator thisArbitrator = user.getRegisteredArbitrator();
NodeAddress thisAddress = p2PService.getNetworkNode().getNodeAddress();
if (thisArbitrator == null || !thisArbitrator.getNodeAddress().equals(thisAddress)) {
errorMessage = "Cannot sign offer because we are not a registered arbitrator";

View file

@ -19,7 +19,7 @@ package bisq.core.offer.placeoffer.tasks;
import bisq.core.offer.Offer;
import bisq.core.offer.placeoffer.PlaceOfferModel;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.trade.TradeUtils;
import static com.google.common.base.Preconditions.checkNotNull;
@ -39,7 +39,7 @@ public class MakerProcessesSignOfferResponse extends Task<PlaceOfferModel> {
runInterceptHook();
// validate arbitrator signature
Mediator arbitrator = checkNotNull(model.getUser().getAcceptedMediatorByAddress(offer.getOfferPayload().getArbitratorSigner()), "user.getAcceptedMediatorByAddress(arbitratorSigner) must not be null");
Arbitrator arbitrator = checkNotNull(model.getUser().getAcceptedArbitratorByAddress(offer.getOfferPayload().getArbitratorSigner()), "user.getAcceptedArbitratorByAddress(arbitratorSigner) must not be null");
if (!TradeUtils.isArbitratorSignatureValid(model.getSignOfferResponse().getSignedOfferPayload(), arbitrator)) {
throw new RuntimeException("Offer payload has invalid arbitrator signature");
}

View file

@ -26,7 +26,7 @@ import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.offer.Offer;
import bisq.core.offer.messages.SignOfferRequest;
import bisq.core.offer.placeoffer.PlaceOfferModel;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.network.p2p.AckMessage;
import bisq.network.p2p.DecryptedDirectMessageListener;
import bisq.network.p2p.DecryptedMessageWithPubKey;
@ -74,7 +74,7 @@ public class MakerSendsSignOfferRequest extends Task<PlaceOfferModel> {
returnAddress);
// get signing arbitrator
Mediator arbitrator = checkNotNull(model.getUser().getAcceptedMediatorByAddress(offer.getOfferPayload().getArbitratorSigner()), "user.getAcceptedMediatorByAddress(mediatorNodeAddress) must not be null");
Arbitrator arbitrator = checkNotNull(model.getUser().getAcceptedArbitratorByAddress(offer.getOfferPayload().getArbitratorSigner()), "user.getAcceptedArbitratorByAddress(arbitratorNodeAddress) must not be null");
// complete on successful ack message
DecryptedDirectMessageListener ackListener = new DecryptedDirectMessageListener() {

View file

@ -75,8 +75,6 @@ public class ValidateOffer extends Task<PlaceOfferModel> {
checkArgument(offer.getDate().getTime() > 0,
"Date must not be 0. date=" + offer.getDate().toString());
System.out.println("OFFER PRICE: " + offer.getPrice());
checkNotNull(offer.getCurrencyCode(), "Currency is null");
checkNotNull(offer.getDirection(), "Direction is null");

View file

@ -31,8 +31,8 @@ import bisq.core.offer.SignedOffer;
import bisq.core.offer.availability.OfferAvailabilityModel;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
import bisq.core.trade.Trade.Phase;
import bisq.core.trade.closed.ClosedTradableManager;
@ -374,7 +374,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
if (isArbitrator) {
// verify this node is registered arbitrator
Mediator thisArbitrator = user.getRegisteredMediator();
Arbitrator thisArbitrator = user.getRegisteredArbitrator();
NodeAddress thisAddress = p2PService.getNetworkNode().getNodeAddress();
if (thisArbitrator == null || !thisArbitrator.getNodeAddress().equals(thisAddress)) {
log.warn("Ignoring InitTradeRequest from {} with tradeId {} because we are not an arbitrator", sender, request.getTradeId());
@ -508,7 +508,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
//System.out.println("TradeManager trade.setTradingPeerNodeAddress(): " + sender);
//trade.setTradingPeerNodeAddress(sender);
// TODO (woodser): what if maker's address changes while offer open, or taker's address changes after multisig deposit available? need to verify and update. see OpenOfferManager.maybeUpdatePersistedOffers()
trade.setArbitratorPubKeyRing(user.getAcceptedMediatorByAddress(sender).getPubKeyRing());
trade.setArbitratorPubKeyRing(user.getAcceptedArbitratorByAddress(sender).getPubKeyRing());
trade.setMakerPubKeyRing(trade.getOffer().getPubKeyRing());
initTradeAndProtocol(trade, getTradeProtocol(trade));
trade.getSelf().setReserveTxHash(openOffer.getReserveTxHash()); // TODO (woodser): initialize in initTradeAndProtocol?

View file

@ -24,7 +24,7 @@ import bisq.common.util.Tuple2;
import bisq.common.util.Utilities;
import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.offer.OfferPayload;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.trade.messages.InitTradeRequest;
import java.util.Objects;
@ -47,7 +47,7 @@ public class TradeUtils {
* @param signedOfferPayload is a signed offer payload
* @return true if the arbitrator's signature is valid for the offer
*/
public static boolean isArbitratorSignatureValid(OfferPayload signedOfferPayload, Mediator arbitrator) {
public static boolean isArbitratorSignatureValid(OfferPayload signedOfferPayload, Arbitrator arbitrator) {
// remove arbitrator signature from signed payload
String signature = signedOfferPayload.getArbitratorSignature();

View file

@ -17,7 +17,7 @@
package bisq.core.trade.protocol.tasks.taker;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.trade.Trade;
import bisq.core.trade.messages.InitTradeRequest;
import bisq.core.trade.protocol.tasks.TradeTask;
@ -80,7 +80,7 @@ public class TakerSendsInitTradeRequestToArbitrator extends TradeTask {
private void sendInitTradeRequest(NodeAddress arbitratorNodeAddress, SendDirectMessageListener listener) {
// get registered arbitrator
Mediator arbitrator = processModel.getUser().getAcceptedMediatorByAddress(arbitratorNodeAddress);
Arbitrator arbitrator = processModel.getUser().getAcceptedArbitratorByAddress(arbitratorNodeAddress);
if (arbitrator == null) throw new RuntimeException("Node address " + arbitratorNodeAddress + " is not a registered arbitrator");
// set pub keys

View file

@ -1374,6 +1374,7 @@ setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature t
# Account
####################################################################
account.tab.arbitratorRegistration=Arbitrator registration
account.tab.mediatorRegistration=Mediator registration
account.tab.refundAgentRegistration=Refund agent registration
account.tab.signing=Signing

View file

@ -125,7 +125,13 @@ public class AccountView extends ActivatableView<TabPane, Void> {
};
keyEventEventHandler = event -> {
if (Utilities.isAltOrCtrlPressed(KeyCode.D, event) && mediatorRegistrationTab == null) {
if (Utilities.isAltOrCtrlPressed(KeyCode.R, event) && arbitratorRegistrationTab == null) {
closeOtherExtraTabs(arbitratorRegistrationTab);
arbitratorRegistrationTab = new Tab(Res.get("account.tab.arbitratorRegistration").toUpperCase());
arbitratorRegistrationTab.setClosable(true);
root.getTabs().add(arbitratorRegistrationTab);
navigation.navigateTo(MainView.class, AccountView.class, ArbitratorRegistrationView.class);
} else if (Utilities.isAltOrCtrlPressed(KeyCode.D, event) && mediatorRegistrationTab == null) {
closeOtherExtraTabs(mediatorRegistrationTab);
mediatorRegistrationTab = new Tab(Res.get("account.tab.mediatorRegistration").toUpperCase());
mediatorRegistrationTab.setClosable(true);

View file

@ -782,15 +782,9 @@ public class GUIUtil {
public static boolean canCreateOrTakeOfferOrShowPopup(User user, Navigation navigation) {
// TODO (woodser): use refund agents to dispute arbitration?
if (!user.hasAcceptedRefundAgents()) {
log.warn("There are no refund agents available"); // TODO (woodser): refund agents changing from [4444] to [] causing this error
//new Popup().warning(Res.get("popup.warning.noArbitratorsAvailable")).show();
//return false;
}
if (!user.hasAcceptedMediators()) {
new Popup().warning(Res.get("popup.warning.noMediatorsAvailable")).show();
if (!user.hasAcceptedArbitrators()) {
log.warn("There are no arbitrators available");
new Popup().warning(Res.get("popup.warning.noArbitratorsAvailable")).show();
return false;
}

View file

@ -35,9 +35,8 @@ If you don't use *screen*, open 4 terminal windows and run in each one of them:
1. `make seednode`
2. `make arbitrator-desktop`
3. If this is the first time launching the arbitrator desktop application, register the arbitrator and mediator after the interface opens:
1. Go to the *Account* tab and press `cmd+n`. Confirm the registration of the arbitrator.
2. From the *Account* tab press `cmd+d` and confirm the registration of the mediator.
3. If this is the first time launching the arbitrator desktop application, register the arbitrator after the interface opens:
1. Go to the *Account* tab and press `cmd+r`. Confirm the registration of the arbitrator.
4. `make alice-desktop` or if you want to run Alice as a daemon: `make alice-daemon`
5. `make bob-desktop` or if you want to run Bob as a daemon: `make bob-daemon`