mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Merge pull request #4353 from sqrrm/signer-send-witness-to-signee
Signer send witness to signee
This commit is contained in:
commit
592cfa1ca0
8 changed files with 189 additions and 12 deletions
|
@ -117,7 +117,7 @@ public class SignedWitness implements ProcessOncePersistableNetworkPayload, Pers
|
|||
return protobuf.PersistableNetworkPayload.newBuilder().setSignedWitness(builder).build();
|
||||
}
|
||||
|
||||
protobuf.SignedWitness toProtoSignedWitness() {
|
||||
public protobuf.SignedWitness toProtoSignedWitness() {
|
||||
return toProtoMessage().getSignedWitness();
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -203,6 +204,17 @@ public class SignedWitnessService {
|
|||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public boolean publishOwnSignedWitness(SignedWitness signedWitness) {
|
||||
if (!Arrays.equals(signedWitness.getWitnessOwnerPubKey(), keyRing.getPubKeyRing().getSignaturePubKeyBytes()) ||
|
||||
!verifySigner(signedWitness)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("Publish own signedWitness {}", signedWitness);
|
||||
publishSignedWitness(signedWitness);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Arbitrators sign with EC key
|
||||
public void signAccountAgeWitness(Coin tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
|
@ -267,17 +279,17 @@ public class SignedWitnessService {
|
|||
}
|
||||
|
||||
// Any peer can sign with DSA key
|
||||
public void signAccountAgeWitness(Coin tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
PublicKey peersPubKey) throws CryptoException {
|
||||
public Optional<SignedWitness> signAccountAgeWitness(Coin tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
PublicKey peersPubKey) throws CryptoException {
|
||||
if (isSignedAccountAgeWitness(accountAgeWitness)) {
|
||||
log.warn("Trader trying to sign already signed accountagewitness {}", accountAgeWitness.toString());
|
||||
return;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (!isSufficientTradeAmountForSigning(tradeAmount)) {
|
||||
log.warn("Trader tried to sign account with too little trade amount");
|
||||
return;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
byte[] signature = Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), accountAgeWitness.getHash());
|
||||
|
@ -290,6 +302,7 @@ public class SignedWitnessService {
|
|||
tradeAmount.value);
|
||||
publishSignedWitness(signedWitness);
|
||||
log.info("Trader signed witness {}", signedWitness.toString());
|
||||
return Optional.of(signedWitness);
|
||||
}
|
||||
|
||||
public boolean verifySignature(SignedWitness signedWitness) {
|
||||
|
@ -366,8 +379,8 @@ public class SignedWitnessService {
|
|||
var oldestUnsignedSigners = new HashMap<P2PDataStorage.ByteArray, SignedWitness>();
|
||||
getRootSignedWitnessSet(false).forEach(signedWitness ->
|
||||
oldestUnsignedSigners.compute(new P2PDataStorage.ByteArray(signedWitness.getSignerPubKey()),
|
||||
(key, oldValue) -> oldValue == null ? signedWitness :
|
||||
oldValue.getDate() > signedWitness.getDate() ? signedWitness : oldValue));
|
||||
(key, oldValue) -> oldValue == null ? signedWitness :
|
||||
oldValue.getDate() > signedWitness.getDate() ? signedWitness : oldValue));
|
||||
return new HashSet<>(oldestUnsignedSigners.values());
|
||||
}
|
||||
|
||||
|
@ -393,6 +406,11 @@ public class SignedWitnessService {
|
|||
return !tradeAmount.isLessThan(MINIMUM_TRADE_AMOUNT_FOR_SIGNING);
|
||||
}
|
||||
|
||||
private boolean verifySigner(SignedWitness signedWitness) {
|
||||
return getSignedWitnessSetByOwnerPubKey(signedWitness.getWitnessOwnerPubKey(), new Stack<>()).stream()
|
||||
.anyMatch(w -> isValidSignerWitnessInternal(w, signedWitness.getDate(), new Stack<>()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the accountAgeWitness has a valid signature from a peer/arbitrator and is allowed to sign
|
||||
* other accounts.
|
||||
|
@ -417,7 +435,7 @@ public class SignedWitnessService {
|
|||
* Helper to isValidAccountAgeWitness(accountAgeWitness)
|
||||
*
|
||||
* @param signedWitness the signedWitness to validate
|
||||
* @param childSignedWitnessDateMillis the date the child SignedWitness was signed or current time if it is a leave.
|
||||
* @param childSignedWitnessDateMillis the date the child SignedWitness was signed or current time if it is a leaf.
|
||||
* @param excludedPubKeys stack to prevent recursive loops
|
||||
* @return true if signedWitness is valid, false otherwise.
|
||||
*/
|
||||
|
|
|
@ -668,7 +668,7 @@ public class AccountAgeWitnessService {
|
|||
signedWitnessService.signAccountAgeWitness(accountAgeWitness, key, tradersPubKey, time);
|
||||
}
|
||||
|
||||
public void traderSignPeersAccountAgeWitness(Trade trade) {
|
||||
public Optional<SignedWitness> traderSignPeersAccountAgeWitness(Trade trade) {
|
||||
AccountAgeWitness peersWitness = findTradePeerWitness(trade).orElse(null);
|
||||
Coin tradeAmount = trade.getTradeAmount();
|
||||
checkNotNull(trade.getProcessModel().getTradingPeer().getPubKeyRing(), "Peer must have a keyring");
|
||||
|
@ -678,10 +678,15 @@ public class AccountAgeWitnessService {
|
|||
checkNotNull(peersPubKey, "Peers pub key must not be null");
|
||||
|
||||
try {
|
||||
signedWitnessService.signAccountAgeWitness(tradeAmount, peersWitness, peersPubKey);
|
||||
return signedWitnessService.signAccountAgeWitness(tradeAmount, peersWitness, peersPubKey);
|
||||
} catch (CryptoException e) {
|
||||
log.warn("Trader failed to sign witness, exception {}", e.toString());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public boolean publishOwnSignedWitness(SignedWitness signedWitness) {
|
||||
return signedWitnessService.publishOwnSignedWitness(signedWitness);
|
||||
}
|
||||
|
||||
// Arbitrator signing
|
||||
|
|
|
@ -58,6 +58,7 @@ import bisq.core.trade.messages.MediatedPayoutTxSignatureMessage;
|
|||
import bisq.core.trade.messages.PayoutTxPublishedMessage;
|
||||
import bisq.core.trade.messages.PeerPublishedDelayedPayoutTxMessage;
|
||||
import bisq.core.trade.messages.RefreshTradeStateRequest;
|
||||
import bisq.core.trade.messages.TraderSignedWitnessMessage;
|
||||
import bisq.core.trade.statistics.TradeStatistics;
|
||||
|
||||
import bisq.network.p2p.AckMessage;
|
||||
|
@ -165,6 +166,8 @@ public class CoreNetworkProtoResolver extends CoreProtoResolver implements Netwo
|
|||
return PayoutTxPublishedMessage.fromProto(proto.getPayoutTxPublishedMessage(), messageVersion);
|
||||
case PEER_PUBLISHED_DELAYED_PAYOUT_TX_MESSAGE:
|
||||
return PeerPublishedDelayedPayoutTxMessage.fromProto(proto.getPeerPublishedDelayedPayoutTxMessage(), messageVersion);
|
||||
case TRADER_SIGNED_WITNESS_MESSAGE:
|
||||
return TraderSignedWitnessMessage.fromProto(proto.getTraderSignedWitnessMessage(), messageVersion);
|
||||
|
||||
case MEDIATED_PAYOUT_TX_SIGNATURE_MESSAGE:
|
||||
return MediatedPayoutTxSignatureMessage.fromProto(proto.getMediatedPayoutTxSignatureMessage(), messageVersion);
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.trade.messages;
|
||||
|
||||
import bisq.core.account.sign.SignedWitness;
|
||||
|
||||
import bisq.network.p2p.MailboxMessage;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Value
|
||||
public class TraderSignedWitnessMessage extends TradeMessage implements MailboxMessage {
|
||||
private final NodeAddress senderNodeAddress;
|
||||
private final SignedWitness signedWitness;
|
||||
|
||||
public TraderSignedWitnessMessage(String uid,
|
||||
String tradeId,
|
||||
NodeAddress senderNodeAddress,
|
||||
SignedWitness signedWitness) {
|
||||
this(Version.getP2PMessageVersion(),
|
||||
uid,
|
||||
tradeId,
|
||||
senderNodeAddress,
|
||||
signedWitness);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private TraderSignedWitnessMessage(int messageVersion,
|
||||
String uid,
|
||||
String tradeId,
|
||||
NodeAddress senderNodeAddress,
|
||||
SignedWitness signedWitness) {
|
||||
super(messageVersion, tradeId, uid);
|
||||
this.senderNodeAddress = senderNodeAddress;
|
||||
this.signedWitness = signedWitness;
|
||||
}
|
||||
|
||||
@Override
|
||||
public protobuf.NetworkEnvelope toProtoNetworkEnvelope() {
|
||||
final protobuf.TraderSignedWitnessMessage.Builder builder = protobuf.TraderSignedWitnessMessage.newBuilder();
|
||||
builder.setUid(uid)
|
||||
.setTradeId(tradeId)
|
||||
.setSenderNodeAddress(senderNodeAddress.toProtoMessage())
|
||||
.setSignedWitness(signedWitness.toProtoSignedWitness());
|
||||
return getNetworkEnvelopeBuilder().setTraderSignedWitnessMessage(builder).build();
|
||||
}
|
||||
|
||||
public static TraderSignedWitnessMessage fromProto(protobuf.TraderSignedWitnessMessage proto, int messageVersion) {
|
||||
return new TraderSignedWitnessMessage(messageVersion,
|
||||
proto.getUid(),
|
||||
proto.getTradeId(),
|
||||
NodeAddress.fromProto(proto.getSenderNodeAddress()),
|
||||
SignedWitness.fromProto(proto.getSignedWitness()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TraderSignedWitnessMessage{" +
|
||||
"\n senderNodeAddress=" + senderNodeAddress +
|
||||
"\n signedWitness=" + signedWitness +
|
||||
"\n} " + super.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ import bisq.core.trade.messages.MediatedPayoutTxPublishedMessage;
|
|||
import bisq.core.trade.messages.MediatedPayoutTxSignatureMessage;
|
||||
import bisq.core.trade.messages.PeerPublishedDelayedPayoutTxMessage;
|
||||
import bisq.core.trade.messages.TradeMessage;
|
||||
import bisq.core.trade.messages.TraderSignedWitnessMessage;
|
||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||
import bisq.core.trade.protocol.tasks.ProcessPeerPublishedDelayedPayoutTxMessage;
|
||||
import bisq.core.trade.protocol.tasks.mediation.BroadcastMediatedPayoutTx;
|
||||
|
@ -228,6 +229,15 @@ public abstract class TradeProtocol {
|
|||
taskRunner.run();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Peer has sent a SignedWitness
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void handle(TraderSignedWitnessMessage tradeMessage) {
|
||||
// Publish signed witness, if it is valid and ours
|
||||
processModel.getAccountAgeWitnessService().publishOwnSignedWitness(tradeMessage.getSignedWitness());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Dispatcher
|
||||
|
@ -240,6 +250,8 @@ public abstract class TradeProtocol {
|
|||
handle((MediatedPayoutTxPublishedMessage) tradeMessage, sender);
|
||||
} else if (tradeMessage instanceof PeerPublishedDelayedPayoutTxMessage) {
|
||||
handle((PeerPublishedDelayedPayoutTxMessage) tradeMessage, sender);
|
||||
} else if (tradeMessage instanceof TraderSignedWitnessMessage) {
|
||||
handle((TraderSignedWitnessMessage) tradeMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,6 +299,8 @@ public abstract class TradeProtocol {
|
|||
handle((MediatedPayoutTxPublishedMessage) tradeMessage, peerNodeAddress);
|
||||
} else if (tradeMessage instanceof PeerPublishedDelayedPayoutTxMessage) {
|
||||
handle((PeerPublishedDelayedPayoutTxMessage) tradeMessage, peerNodeAddress);
|
||||
} else if (tradeMessage instanceof TraderSignedWitnessMessage) {
|
||||
handle((TraderSignedWitnessMessage) tradeMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import bisq.desktop.common.model.ViewModel;
|
|||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.account.sign.SignedWitness;
|
||||
import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
|
@ -33,13 +34,17 @@ import bisq.core.provider.fee.FeeService;
|
|||
import bisq.core.trade.Contract;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.closed.ClosedTradableManager;
|
||||
import bisq.core.trade.messages.RefreshTradeStateRequest;
|
||||
import bisq.core.trade.messages.TraderSignedWitnessMessage;
|
||||
import bisq.core.user.User;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.core.util.validation.BtcAddressValidator;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.P2PService;
|
||||
import bisq.network.p2p.SendMailboxMessageListener;
|
||||
|
||||
import bisq.common.ClockWatcher;
|
||||
import bisq.common.app.DevEnv;
|
||||
|
@ -58,6 +63,7 @@ import javafx.beans.property.ReadOnlyObjectProperty;
|
|||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.Getter;
|
||||
|
@ -383,10 +389,45 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||
|
||||
public void maybeSignWitness() {
|
||||
if (isSignWitnessTrade()) {
|
||||
accountAgeWitnessService.traderSignPeersAccountAgeWitness(trade);
|
||||
var signedWitness = accountAgeWitnessService.traderSignPeersAccountAgeWitness(trade);
|
||||
signedWitness.ifPresent(this::sendSignedWitnessToPeer);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSignedWitnessToPeer(SignedWitness signedWitness) {
|
||||
Trade trade = getTrade();
|
||||
if (trade == null) return;
|
||||
|
||||
NodeAddress tradingPeerNodeAddress = trade.getTradingPeerNodeAddress();
|
||||
var traderSignedWitnessMessage = new TraderSignedWitnessMessage(UUID.randomUUID().toString(), trade.getId(),
|
||||
tradingPeerNodeAddress, signedWitness);
|
||||
|
||||
p2PService.sendEncryptedMailboxMessage(
|
||||
tradingPeerNodeAddress,
|
||||
trade.getProcessModel().getTradingPeer().getPubKeyRing(),
|
||||
traderSignedWitnessMessage,
|
||||
new SendMailboxMessageListener() {
|
||||
@Override
|
||||
public void onArrived() {
|
||||
log.info("SendMailboxMessageListener onArrived tradeId={} at peer {} SignedWitness {}",
|
||||
trade.getId(), tradingPeerNodeAddress, signedWitness);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStoredInMailbox() {
|
||||
log.info("SendMailboxMessageListener onStoredInMailbox tradeId={} at peer {} SignedWitness {}",
|
||||
trade.getId(), tradingPeerNodeAddress, signedWitness);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFault(String errorMessage) {
|
||||
log.error("SendMailboxMessageListener onFault tradeId={} at peer {} SignedWitness {}",
|
||||
trade.getId(), tradingPeerNodeAddress, signedWitness);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// States
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -77,6 +77,7 @@ message NetworkEnvelope {
|
|||
PeerPublishedDelayedPayoutTxMessage peer_published_delayed_payout_tx_message = 49;
|
||||
|
||||
RefreshTradeStateRequest refresh_trade_state_request = 50;
|
||||
TraderSignedWitnessMessage trader_signed_witness_message = 51;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,6 +330,13 @@ message RefreshTradeStateRequest {
|
|||
NodeAddress sender_node_address = 3;
|
||||
}
|
||||
|
||||
message TraderSignedWitnessMessage {
|
||||
string uid = 1;
|
||||
string trade_id = 2;
|
||||
NodeAddress sender_node_address = 3;
|
||||
SignedWitness signed_witness = 4;
|
||||
}
|
||||
|
||||
// dispute
|
||||
|
||||
enum SupportType {
|
||||
|
|
Loading…
Add table
Reference in a new issue