verify offer versions when signing

This commit is contained in:
woodser 2025-03-20 08:04:30 -04:00 committed by woodser
parent bee86daff3
commit b5f9bc307b
5 changed files with 55 additions and 7 deletions
common/src/main/java/haveno/common/app
core/src/main/java/haveno/core

View file

@ -72,6 +72,25 @@ public class Version {
return false;
}
public static int compare(String version1, String version2) {
if (version1.equals(version2))
return 0;
else if (getMajorVersion(version1) > getMajorVersion(version2))
return 1;
else if (getMajorVersion(version1) < getMajorVersion(version2))
return -1;
else if (getMinorVersion(version1) > getMinorVersion(version2))
return 1;
else if (getMinorVersion(version1) < getMinorVersion(version2))
return -1;
else if (getPatchVersion(version1) > getPatchVersion(version2))
return 1;
else if (getPatchVersion(version1) < getPatchVersion(version2))
return -1;
else
return 0;
}
private static int getSubVersion(String version, int index) {
final String[] split = version.split("\\.");
checkArgument(split.length == 3, "Version number must be in semantic version format (contain 2 '.'). version=" + version);

View file

@ -178,6 +178,9 @@ public class DomainInitialisation {
closedTradableManager.onAllServicesInitialized();
failedTradesManager.onAllServicesInitialized();
filterManager.setFilterWarningHandler(filterWarningHandler);
filterManager.onAllServicesInitialized();
openOfferManager.onAllServicesInitialized();
balances.onAllServicesInitialized();
@ -199,10 +202,6 @@ public class DomainInitialisation {
priceFeedService.setCurrencyCodeOnInit();
priceFeedService.startRequestingPrices();
filterManager.setFilterWarningHandler(filterWarningHandler);
filterManager.onAllServicesInitialized();
mobileNotificationService.onAllServicesInitialized();
myOfferTakenEvents.onAllServicesInitialized();
tradeEvents.onAllServicesInitialized();

View file

@ -406,6 +406,10 @@ public class FilterManager {
.anyMatch(e -> e.equals(address));
}
public String getDisableTradeBelowVersion() {
return getFilter() == null || getFilter().getDisableTradeBelowVersion() == null || getFilter().getDisableTradeBelowVersion().isEmpty() ? null : getFilter().getDisableTradeBelowVersion();
}
public boolean requireUpdateToNewVersionForTrading() {
if (getFilter() == null) {
return false;

View file

@ -737,7 +737,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
doCancelOffer(openOffer, true);
}
// remove open offer which thaws its key images
// cancel open offer which thaws its key images
private void doCancelOffer(@NotNull OpenOffer openOffer, boolean resetAddressEntries) {
Offer offer = openOffer.getOffer();
offer.setState(Offer.State.REMOVED);
@ -1396,6 +1396,32 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
return;
}
// verify the trade protocol version
if (request.getOfferPayload().getProtocolVersion() != Version.TRADE_PROTOCOL_VERSION) {
errorMessage = "Unsupported protocol version: " + request.getOfferPayload().getProtocolVersion();
log.warn(errorMessage);
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage);
return;
}
// verify the min version number
if (filterManager.getDisableTradeBelowVersion() != null) {
if (Version.compare(request.getOfferPayload().getVersionNr(), filterManager.getDisableTradeBelowVersion()) < 0) {
errorMessage = "Offer version number is too low: " + request.getOfferPayload().getVersionNr() + " < " + filterManager.getDisableTradeBelowVersion();
log.warn(errorMessage);
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage);
return;
}
}
// verify the max version number
if (Version.compare(request.getOfferPayload().getVersionNr(), Version.VERSION) > 0) {
errorMessage = "Offer version number is too high: " + request.getOfferPayload().getVersionNr() + " > " + Version.VERSION;
log.warn(errorMessage);
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage);
return;
}
// verify maker and taker fees
boolean hasBuyerAsTakerWithoutDeposit = offer.getDirection() == OfferDirection.SELL && offer.isPrivateOffer() && offer.getChallengeHash() != null && offer.getChallengeHash().length() > 0 && offer.getTakerFeePct() == 0;
if (hasBuyerAsTakerWithoutDeposit) {

View file

@ -767,7 +767,7 @@ public class XmrWalletService extends XmrWalletBase {
BigInteger minerFeeEstimate = getFeeEstimate(tx.getWeight());
double minerFeeDiff = tx.getFee().subtract(minerFeeEstimate).abs().doubleValue() / minerFeeEstimate.doubleValue();
if (minerFeeDiff > MINER_FEE_TOLERANCE) throw new RuntimeException("Miner fee is not within " + (MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + minerFeeEstimate + " but was " + tx.getFee() + ", diff%=" + minerFeeDiff);
log.info("Trade tx fee {} is within tolerance, diff%={}", tx.getFee(), minerFeeDiff);
log.info("Trade miner fee {} is within tolerance, diff%={}", tx.getFee(), minerFeeDiff);
// verify proof to fee address
BigInteger actualTradeFee = BigInteger.ZERO;
@ -785,7 +785,7 @@ public class XmrWalletService extends XmrWalletBase {
// verify trade fee amount
if (!actualTradeFee.equals(tradeFeeAmount)) {
if (equalsWithinFractionError(actualTradeFee, tradeFeeAmount)) {
log.warn("Trade tx fee amount is within fraction error, expected " + tradeFeeAmount + " but was " + actualTradeFee);
log.warn("Trade fee amount is within fraction error, expected " + tradeFeeAmount + " but was " + actualTradeFee);
} else {
throw new RuntimeException("Invalid trade fee amount, expected " + tradeFeeAmount + " but was " + actualTradeFee);
}