Skip to content

Commit

Permalink
Merge pull request #4524 from ghubstan/1-register-regest-dispute-agents
Browse files Browse the repository at this point in the history
Add core support for registration of regtest dispute agents via API
  • Loading branch information
sqrrm authored Sep 16, 2020
2 parents 8cb4b50 + 57423f4 commit b812a26
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 7 deletions.
3 changes: 3 additions & 0 deletions cli/src/main/java/bisq/cli/GrpcStubs.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package bisq.cli;

import bisq.proto.grpc.DisputeAgentsGrpc;
import bisq.proto.grpc.GetVersionGrpc;
import bisq.proto.grpc.OffersGrpc;
import bisq.proto.grpc.PaymentAccountsGrpc;
Expand All @@ -29,6 +30,7 @@

public class GrpcStubs {

public final DisputeAgentsGrpc.DisputeAgentsBlockingStub disputeAgentsService;
public final GetVersionGrpc.GetVersionBlockingStub versionService;
public final OffersGrpc.OffersBlockingStub offersService;
public final PaymentAccountsGrpc.PaymentAccountsBlockingStub paymentAccountsService;
Expand All @@ -46,6 +48,7 @@ public GrpcStubs(String apiHost, int apiPort, String apiPassword) {
}
}));

this.disputeAgentsService = DisputeAgentsGrpc.newBlockingStub(channel).withCallCredentials(credentials);
this.versionService = GetVersionGrpc.newBlockingStub(channel).withCallCredentials(credentials);
this.offersService = OffersGrpc.newBlockingStub(channel).withCallCredentials(credentials);
this.paymentAccountsService = PaymentAccountsGrpc.newBlockingStub(channel).withCallCredentials(credentials);
Expand Down
14 changes: 13 additions & 1 deletion core/src/main/java/bisq/core/api/CoreApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,38 @@
@Slf4j
public class CoreApi {

private final CoreDisputeAgentsService coreDisputeAgentsService;
private final CoreOffersService coreOffersService;
private final CorePaymentAccountsService paymentAccountsService;
private final CoreWalletsService walletsService;
private final TradeStatisticsManager tradeStatisticsManager;

@Inject
public CoreApi(CoreOffersService coreOffersService,
public CoreApi(CoreDisputeAgentsService coreDisputeAgentsService,
CoreOffersService coreOffersService,
CorePaymentAccountsService paymentAccountsService,
CoreWalletsService walletsService,
TradeStatisticsManager tradeStatisticsManager) {
this.coreDisputeAgentsService = coreDisputeAgentsService;
this.coreOffersService = coreOffersService;
this.paymentAccountsService = paymentAccountsService;
this.walletsService = walletsService;
this.tradeStatisticsManager = tradeStatisticsManager;
}

@SuppressWarnings("SameReturnValue")
public String getVersion() {
return Version.VERSION;
}

///////////////////////////////////////////////////////////////////////////////////////////
// Dispute Agents
///////////////////////////////////////////////////////////////////////////////////////////

public void registerDisputeAgent(String disputeAgentType, String registrationKey) {
coreDisputeAgentsService.registerDisputeAgent(disputeAgentType, registrationKey);
}

///////////////////////////////////////////////////////////////////////////////////////////
// Offers
///////////////////////////////////////////////////////////////////////////////////////////
Expand Down
144 changes: 144 additions & 0 deletions core/src/main/java/bisq/core/api/CoreDisputeAgentsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.core.api;

import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
import bisq.core.support.dispute.refund.refundagent.RefundAgent;
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;

import bisq.network.p2p.NodeAddress;
import bisq.network.p2p.P2PService;

import bisq.common.config.Config;
import bisq.common.crypto.KeyRing;

import org.bitcoinj.core.ECKey;

import javax.inject.Inject;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import lombok.extern.slf4j.Slf4j;

import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY;
import static java.net.InetAddress.getLoopbackAddress;

@Slf4j
class CoreDisputeAgentsService {

private final Config config;
private final KeyRing keyRing;
private final MediatorManager mediatorManager;
private final RefundAgentManager refundAgentManager;
private final P2PService p2PService;
private final NodeAddress nodeAddress;
private final List<String> languageCodes;

@Inject
public CoreDisputeAgentsService(Config config,
KeyRing keyRing,
MediatorManager mediatorManager,
RefundAgentManager refundAgentManager,
P2PService p2PService) {
this.config = config;
this.keyRing = keyRing;
this.mediatorManager = mediatorManager;
this.refundAgentManager = refundAgentManager;
this.p2PService = p2PService;
this.nodeAddress = new NodeAddress(getLoopbackAddress().getHostAddress(), config.nodePort);
this.languageCodes = Arrays.asList("de", "en", "es", "fr");
}

public void registerDisputeAgent(String disputeAgentType, String registrationKey) {
if (!p2PService.isBootstrapped())
throw new IllegalStateException("p2p service is not bootstrapped yet");

if (config.baseCurrencyNetwork.isMainnet()
|| config.baseCurrencyNetwork.isDaoBetaNet()
|| !config.useLocalhostForP2P)
throw new IllegalStateException("dispute agents must be registered in a Bisq UI");

if (!registrationKey.equals(DEV_PRIVILEGE_PRIV_KEY))
throw new IllegalArgumentException("invalid registration key");

ECKey ecKey;
String signature;
switch (disputeAgentType) {
case "arbitrator":
throw new IllegalArgumentException("arbitrators must be registered in a Bisq UI");
case "mediator":
ecKey = mediatorManager.getRegistrationKey(registrationKey);
signature = mediatorManager.signStorageSignaturePubKey(Objects.requireNonNull(ecKey));
registerMediator(nodeAddress, languageCodes, ecKey, signature);
return;
case "refundagent":
ecKey = refundAgentManager.getRegistrationKey(registrationKey);
signature = refundAgentManager.signStorageSignaturePubKey(Objects.requireNonNull(ecKey));
registerRefundAgent(nodeAddress, languageCodes, ecKey, signature);
return;
default:
throw new IllegalArgumentException("unknown dispute agent type " + disputeAgentType);
}
}

private void registerMediator(NodeAddress nodeAddress,
List<String> languageCodes,
ECKey ecKey,
String signature) {
Mediator mediator = new Mediator(nodeAddress,
keyRing.getPubKeyRing(),
languageCodes,
new Date().getTime(),
ecKey.getPubKey(),
signature,
null,
null,
null
);
mediatorManager.addDisputeAgent(mediator, () -> {
}, errorMessage -> {
});
mediatorManager.getDisputeAgentByNodeAddress(nodeAddress).orElseThrow(() ->
new IllegalStateException("could not register mediator"));
}

private void registerRefundAgent(NodeAddress nodeAddress,
List<String> languageCodes,
ECKey ecKey,
String signature) {
RefundAgent refundAgent = new RefundAgent(nodeAddress,
keyRing.getPubKeyRing(),
languageCodes,
new Date().getTime(),
ecKey.getPubKey(),
signature,
null,
null,
null
);
refundAgentManager.addDisputeAgent(refundAgent, () -> {
}, errorMessage -> {
});
refundAgentManager.getDisputeAgentByNodeAddress(nodeAddress).orElseThrow(() ->
new IllegalStateException("could not register refund agent"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package bisq.daemon.grpc;

import bisq.core.api.CoreApi;

import bisq.proto.grpc.DisputeAgentsGrpc;
import bisq.proto.grpc.RegisterDisputeAgentReply;
import bisq.proto.grpc.RegisterDisputeAgentRequest;

import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;

import javax.inject.Inject;

import lombok.extern.slf4j.Slf4j;

@Slf4j
class GrpcDisputeAgentsService extends DisputeAgentsGrpc.DisputeAgentsImplBase {

private final CoreApi coreApi;

@Inject
public GrpcDisputeAgentsService(CoreApi coreApi) {
this.coreApi = coreApi;
}

@Override
public void registerDisputeAgent(RegisterDisputeAgentRequest req,
StreamObserver<RegisterDisputeAgentReply> responseObserver) {
try {
coreApi.registerDisputeAgent(req.getDisputeAgentType(), req.getRegistrationKey());
var reply = RegisterDisputeAgentReply.newBuilder().build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
} catch (IllegalArgumentException cause) {
var ex = new StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription(cause.getMessage()));
responseObserver.onError(ex);
throw ex;
} catch (IllegalStateException cause) {
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
responseObserver.onError(ex);
throw ex;
}
}
}
2 changes: 2 additions & 0 deletions daemon/src/main/java/bisq/daemon/grpc/GrpcServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@ public class GrpcServer {
@Inject
public GrpcServer(Config config,
CoreApi coreApi,
GrpcDisputeAgentsService disputeAgentsService,
GrpcOffersService offersService,
GrpcPaymentAccountsService paymentAccountsService,
GrpcWalletsService walletsService) {
this.coreApi = coreApi;
this.server = ServerBuilder.forPort(config.apiPort)
.addService(disputeAgentsService)
.addService(new GetVersionService())
.addService(new GetTradeStatisticsService())
.addService(offersService)
Expand Down
30 changes: 24 additions & 6 deletions proto/src/main/proto/grpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@ option java_package = "bisq.proto.grpc";
option java_multiple_files = true;

///////////////////////////////////////////////////////////////////////////////////////////
// Version
// DisputeAgents
///////////////////////////////////////////////////////////////////////////////////////////

service GetVersion {
rpc GetVersion (GetVersionRequest) returns (GetVersionReply) {
service DisputeAgents {
rpc RegisterDisputeAgent (RegisterDisputeAgentRequest) returns (RegisterDisputeAgentReply) {
}
}

message GetVersionRequest {
message RegisterDisputeAgentRequest {
string disputeAgentType = 1;
string registrationKey = 2;
}

message GetVersionReply {
string version = 1;
message RegisterDisputeAgentReply {
}

///////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -214,3 +215,20 @@ message AddressBalanceInfo {
int64 balance = 2;
int64 numConfirmations = 3;
}

///////////////////////////////////////////////////////////////////////////////////////////
// Version
///////////////////////////////////////////////////////////////////////////////////////////

service GetVersion {
rpc GetVersion (GetVersionRequest) returns (GetVersionReply) {
}
}

message GetVersionRequest {
}

message GetVersionReply {
string version = 1;
}

0 comments on commit b812a26

Please sign in to comment.