Merge pull request #7393 from alvasw/Handle_burning_man_selection_height_edge-cases

Handle burning man selection height edge cases
This commit is contained in:
Alejandro García 2025-02-25 12:52:41 +00:00 committed by GitHub
commit 5c62df3c10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 77 additions and 4 deletions

View file

@ -59,6 +59,8 @@ public class DelayedPayoutTxReceiverService implements DaoStateListener {
// See: https://github.com/bisq-network/proposals/issues/412 // See: https://github.com/bisq-network/proposals/issues/412
public static final Date PROPOSAL_412_ACTIVATION_DATE = Utilities.getUTCDate(2024, GregorianCalendar.MAY, 1); public static final Date PROPOSAL_412_ACTIVATION_DATE = Utilities.getUTCDate(2024, GregorianCalendar.MAY, 1);
public static final int SNAPSHOT_SELECTION_GRID_SIZE = 10;
// We don't allow to get further back than 767950 (the block height from Dec. 18th 2022). // We don't allow to get further back than 767950 (the block height from Dec. 18th 2022).
static final int MIN_SNAPSHOT_HEIGHT = Config.baseCurrencyNetwork().isRegtest() ? 0 : 767950; static final int MIN_SNAPSHOT_HEIGHT = Config.baseCurrencyNetwork().isRegtest() ? 0 : 767950;
@ -116,7 +118,8 @@ public class DelayedPayoutTxReceiverService implements DaoStateListener {
// The block height is the last mod(10) height from the range of the last 10-20 blocks (139 -> 120; 140 -> 130, 141 -> 130). // The block height is the last mod(10) height from the range of the last 10-20 blocks (139 -> 120; 140 -> 130, 141 -> 130).
// We do not have the latest dao state by that but can ensure maker and taker have the same block. // We do not have the latest dao state by that but can ensure maker and taker have the same block.
public int getBurningManSelectionHeight() { public int getBurningManSelectionHeight() {
return getSnapshotHeight(daoStateService.getGenesisBlockHeight(), currentChainHeight, 10); return getSnapshotHeight(daoStateService.getGenesisBlockHeight(), currentChainHeight,
SNAPSHOT_SELECTION_GRID_SIZE);
} }
public List<Tuple2<Long, String>> getReceivers(int burningManSelectionHeight, public List<Tuple2<Long, String>> getReceivers(int burningManSelectionHeight,
@ -214,7 +217,7 @@ public class DelayedPayoutTxReceiverService implements DaoStateListener {
// Borrowed from DaoStateSnapshotService. We prefer to not reuse to avoid dependency to an unrelated domain. // Borrowed from DaoStateSnapshotService. We prefer to not reuse to avoid dependency to an unrelated domain.
@VisibleForTesting @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)) { if (height > (genesisHeight + 3 * grid)) {
int ratio = (int) Math.round(height / (double) grid); int ratio = (int) Math.round(height / (double) grid);
return Math.max(minSnapshotHeight, ratio * grid - grid); return Math.max(minSnapshotHeight, ratio * grid - grid);

View file

@ -47,6 +47,7 @@ import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
import bisq.core.trade.ClosedTradableManager; import bisq.core.trade.ClosedTradableManager;
import bisq.core.trade.bisq_v1.TransactionResultHandler; import bisq.core.trade.bisq_v1.TransactionResultHandler;
import bisq.core.trade.model.TradableList; 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.trade.statistics.TradeStatisticsManager;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.user.User; import bisq.core.user.User;
@ -857,7 +858,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
checkArgument(takersBurningManSelectionHeight > 0, "takersBurningManSelectionHeight must not be 0"); checkArgument(takersBurningManSelectionHeight > 0, "takersBurningManSelectionHeight must not be 0");
int makersBurningManSelectionHeight = delayedPayoutTxReceiverService.getBurningManSelectionHeight(); int makersBurningManSelectionHeight = delayedPayoutTxReceiverService.getBurningManSelectionHeight();
checkArgument(takersBurningManSelectionHeight == makersBurningManSelectionHeight,
boolean areBurningManSelectionHeightsValid = MakerProcessesInputsForDepositTxRequest
.verifyBurningManSelectionHeight(takersBurningManSelectionHeight, makersBurningManSelectionHeight);
checkArgument(areBurningManSelectionHeightsValid,
"takersBurningManSelectionHeight does no match makersBurningManSelectionHeight. " + "takersBurningManSelectionHeight does no match makersBurningManSelectionHeight. " +
"takersBurningManSelectionHeight=" + takersBurningManSelectionHeight + "; makersBurningManSelectionHeight=" + makersBurningManSelectionHeight); "takersBurningManSelectionHeight=" + takersBurningManSelectionHeight + "; makersBurningManSelectionHeight=" + makersBurningManSelectionHeight);
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -17,6 +17,7 @@
package bisq.core.trade.protocol.bisq_v1.tasks.maker; package bisq.core.trade.protocol.bisq_v1.tasks.maker;
import bisq.core.dao.burningman.DelayedPayoutTxReceiverService;
import bisq.core.exceptions.TradePriceOutOfToleranceException; import bisq.core.exceptions.TradePriceOutOfToleranceException;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.support.dispute.mediation.mediator.Mediator; 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"); checkArgument(takersBurningManSelectionHeight > 0, "takersBurningManSelectionHeight must not be 0");
int makersBurningManSelectionHeight = processModel.getDelayedPayoutTxReceiverService().getBurningManSelectionHeight(); int makersBurningManSelectionHeight = processModel.getDelayedPayoutTxReceiverService().getBurningManSelectionHeight();
checkArgument(takersBurningManSelectionHeight == makersBurningManSelectionHeight,
boolean areBurningManSelectionHeightsValid = verifyBurningManSelectionHeight(
takersBurningManSelectionHeight, makersBurningManSelectionHeight);
checkArgument(areBurningManSelectionHeightsValid,
"takersBurningManSelectionHeight does no match makersBurningManSelectionHeight"); "takersBurningManSelectionHeight does no match makersBurningManSelectionHeight");
processModel.setBurningManSelectionHeight(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 // 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); 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;
}
}
} }

View file

@ -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);
}
}