From 96355d7a3cd0ad3cf5d6dfbe62c6cfd28e9a4e45 Mon Sep 17 00:00:00 2001 From: Alva Swanson Date: Thu, 13 Feb 2025 22:56:00 +0000 Subject: [PATCH] Handle burning man selection height edge-cases If trader A's block height is 134 his burning man selection height is 120, and if trader B's block height is 135 his burning man selection height is 130. The current burning man selection height verification code doesn't handle these edge-cases. --- .../DelayedPayoutTxReceiverService.java | 2 +- .../bisq/core/offer/OpenOfferManager.java | 6 ++- ...kerProcessesInputsForDepositTxRequest.java | 24 +++++++++- ...rocessesInputsForDepositTxRequestTest.java | 44 +++++++++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 core/src/test/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequestTest.java diff --git a/core/src/main/java/bisq/core/dao/burningman/DelayedPayoutTxReceiverService.java b/core/src/main/java/bisq/core/dao/burningman/DelayedPayoutTxReceiverService.java index f2a1e0f0ff..bc7da9d4b8 100644 --- a/core/src/main/java/bisq/core/dao/burningman/DelayedPayoutTxReceiverService.java +++ b/core/src/main/java/bisq/core/dao/burningman/DelayedPayoutTxReceiverService.java @@ -217,7 +217,7 @@ public class DelayedPayoutTxReceiverService implements DaoStateListener { // Borrowed from DaoStateSnapshotService. We prefer to not reuse to avoid dependency to an unrelated domain. @VisibleForTesting - static int getSnapshotHeight(int genesisHeight, int height, int grid, int minSnapshotHeight) { + public static int getSnapshotHeight(int genesisHeight, int height, int grid, int minSnapshotHeight) { if (height > (genesisHeight + 3 * grid)) { int ratio = (int) Math.round(height / (double) grid); return Math.max(minSnapshotHeight, ratio * grid - grid); diff --git a/core/src/main/java/bisq/core/offer/OpenOfferManager.java b/core/src/main/java/bisq/core/offer/OpenOfferManager.java index 3e972df040..2b2bcc9900 100644 --- a/core/src/main/java/bisq/core/offer/OpenOfferManager.java +++ b/core/src/main/java/bisq/core/offer/OpenOfferManager.java @@ -47,6 +47,7 @@ import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; import bisq.core.trade.ClosedTradableManager; import bisq.core.trade.bisq_v1.TransactionResultHandler; import bisq.core.trade.model.TradableList; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerProcessesInputsForDepositTxRequest; import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.user.Preferences; import bisq.core.user.User; @@ -857,7 +858,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe checkArgument(takersBurningManSelectionHeight > 0, "takersBurningManSelectionHeight must not be 0"); int makersBurningManSelectionHeight = delayedPayoutTxReceiverService.getBurningManSelectionHeight(); - checkArgument(takersBurningManSelectionHeight == makersBurningManSelectionHeight, + + boolean areBurningManSelectionHeightsValid = MakerProcessesInputsForDepositTxRequest + .verifyBurningManSelectionHeight(takersBurningManSelectionHeight, makersBurningManSelectionHeight); + checkArgument(areBurningManSelectionHeightsValid, "takersBurningManSelectionHeight does no match makersBurningManSelectionHeight. " + "takersBurningManSelectionHeight=" + takersBurningManSelectionHeight + "; makersBurningManSelectionHeight=" + makersBurningManSelectionHeight); } catch (Throwable t) { diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequest.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequest.java index 395d400893..84c9c3bf77 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequest.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequest.java @@ -17,6 +17,7 @@ package bisq.core.trade.protocol.bisq_v1.tasks.maker; +import bisq.core.dao.burningman.DelayedPayoutTxReceiverService; import bisq.core.exceptions.TradePriceOutOfToleranceException; import bisq.core.offer.Offer; import bisq.core.support.dispute.mediation.mediator.Mediator; @@ -83,8 +84,12 @@ public class MakerProcessesInputsForDepositTxRequest extends TradeTask { checkArgument(takersBurningManSelectionHeight > 0, "takersBurningManSelectionHeight must not be 0"); int makersBurningManSelectionHeight = processModel.getDelayedPayoutTxReceiverService().getBurningManSelectionHeight(); - checkArgument(takersBurningManSelectionHeight == makersBurningManSelectionHeight, + + boolean areBurningManSelectionHeightsValid = verifyBurningManSelectionHeight( + takersBurningManSelectionHeight, makersBurningManSelectionHeight); + checkArgument(areBurningManSelectionHeightsValid, "takersBurningManSelectionHeight does no match makersBurningManSelectionHeight"); + processModel.setBurningManSelectionHeight(makersBurningManSelectionHeight); // We set the taker fee only in the processModel yet not in the trade as the tx was only created but not @@ -132,4 +137,21 @@ public class MakerProcessesInputsForDepositTxRequest extends TradeTask { failed(t); } } + + public static boolean verifyBurningManSelectionHeight(int takersBurningManSelectionHeight, + int makersBurningManSelectionHeight) { + if (takersBurningManSelectionHeight == makersBurningManSelectionHeight) { + return true; + + } else if (takersBurningManSelectionHeight < makersBurningManSelectionHeight) { + int takersNextBlockBurningManSelectionHeight = + takersBurningManSelectionHeight + DelayedPayoutTxReceiverService.SNAPSHOT_SELECTION_GRID_SIZE; + return takersNextBlockBurningManSelectionHeight == makersBurningManSelectionHeight; + + } else { + int makersNextBlockBurningManSelectionHeight = + makersBurningManSelectionHeight + DelayedPayoutTxReceiverService.SNAPSHOT_SELECTION_GRID_SIZE; + return takersBurningManSelectionHeight == makersNextBlockBurningManSelectionHeight; + } + } } diff --git a/core/src/test/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequestTest.java b/core/src/test/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequestTest.java new file mode 100644 index 0000000000..1ce0adc6da --- /dev/null +++ b/core/src/test/java/bisq/core/trade/protocol/bisq_v1/tasks/maker/MakerProcessesInputsForDepositTxRequestTest.java @@ -0,0 +1,44 @@ +package bisq.core.trade.protocol.bisq_v1.tasks.maker; + +import bisq.core.dao.burningman.DelayedPayoutTxReceiverService; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class MakerProcessesInputsForDepositTxRequestTest { + private static final int GENESIS_HEIGHT = 102; + private static final int GRID_SIZE = DelayedPayoutTxReceiverService.SNAPSHOT_SELECTION_GRID_SIZE; + + @Test + void burningManSelectionHeightSameBlock() { + assertEquals(130, + DelayedPayoutTxReceiverService.getSnapshotHeight(GENESIS_HEIGHT, 139, GRID_SIZE, 0)); + boolean isValid = MakerProcessesInputsForDepositTxRequest + .verifyBurningManSelectionHeight(130, 130); + assertTrue(isValid); + } + + @Test + void burningManSelectionHeightMakerOneBlockInFuture() { + assertEquals(120, + DelayedPayoutTxReceiverService.getSnapshotHeight(GENESIS_HEIGHT, 134, GRID_SIZE, 0)); + assertEquals(130, + DelayedPayoutTxReceiverService.getSnapshotHeight(GENESIS_HEIGHT, 135, GRID_SIZE, 0)); + boolean isValid = MakerProcessesInputsForDepositTxRequest + .verifyBurningManSelectionHeight(120, 130); + assertTrue(isValid); + } + + @Test + void burningManSelectionHeightTakerOneBlockInFuture() { + assertEquals(120, + DelayedPayoutTxReceiverService.getSnapshotHeight(GENESIS_HEIGHT, 134, GRID_SIZE, 0)); + assertEquals(130, + DelayedPayoutTxReceiverService.getSnapshotHeight(GENESIS_HEIGHT, 135, GRID_SIZE, 0)); + boolean isValid = MakerProcessesInputsForDepositTxRequest + .verifyBurningManSelectionHeight(130, 120); + assertTrue(isValid); + } +}