Skip to content

Commit

Permalink
When rejected pegout is refunded, post RSKIP427 refund the total valu…
Browse files Browse the repository at this point in the history
…e sent in weis
  • Loading branch information
marcos-iov committed Oct 10, 2024
1 parent 46557c4 commit 8e07881
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 12 deletions.
9 changes: 8 additions & 1 deletion rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -850,10 +850,17 @@ private void refundAndEmitRejectEvent(
senderAddress,
reason
);

// Prior to RSKIP427, the value was converted to BTC before doing the refund
// This could cause the original value to be rounded down to fit in satoshis value
co.rsk.core.Coin refundValue = activations.isActive(RSKIP427) ?
releaseRequestedValue :
co.rsk.core.Coin.fromBitcoin(releaseRequestedValue.toBitcoin());

rskRepository.transfer(
PrecompiledContracts.BRIDGE_ADDR,
senderAddress,
releaseRequestedValue
refundValue
);
emitRejectEvent(releaseRequestedValue, senderAddress, reason);
}
Expand Down
67 changes: 56 additions & 11 deletions rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.ethereum.vm.program.InternalTransaction;
import org.ethereum.vm.program.Program;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class BridgeSupportReleaseBtcTest {
Expand Down Expand Up @@ -1260,7 +1261,8 @@ private void testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(
}

@Test
void low_amount_release_request_rejected_before_lovell_value_in_satoshis() throws IOException {
@DisplayName("A rejected pegout due to low amount. Pre lovell, the value is rounded down to the nearest satoshi. Both in the emitted event and the value refunded.")
void low_amount_release_request_rejected_before_lovell() throws IOException {
ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0L);

List<LogInfo> logInfo = new ArrayList<>();
Expand All @@ -1274,15 +1276,22 @@ void low_amount_release_request_rejected_before_lovell_value_in_satoshis() throw

Coin belowPegoutMinimumValue = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().minus(Coin.SATOSHI);
co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(belowPegoutMinimumValue);
// Add some extra weis to the value, but less than 1 satoshi.
// To ensure that the pegout value is rounded down to fit in satoshis.
co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.valueOf(Denomination.satoshisToWeis(1).longValue());
co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(co.rsk.core.Coin.valueOf(1));
pegoutRequestValue = pegoutRequestValue.add(extraWeis);

bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue));

RskAddress senderAddress = new RskAddress(SENDER.getAddress());

// Pre lovell, the refund should be rounded down to the nearest satoshi.
co.rsk.core.Coin expectedRefundValue = pegoutRequestValue.subtract(extraWeis);
verify(repository, times(1)).transfer(
BRIDGE_ADDRESS,
senderAddress,
pegoutRequestValue
expectedRefundValue
);

assertEquals(0, provider.getReleaseRequestQueue().getEntries().size());
Expand All @@ -1299,12 +1308,15 @@ void low_amount_release_request_rejected_before_lovell_value_in_satoshis() throw
CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent();
assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData());

// Same case in the log, the value should be rounded down to the nearest satoshi.
BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0];
assertEquals(pegoutRequestValue.toBitcoin().longValue(), amount.longValue());
long expectedAmountLogged = expectedRefundValue.toBitcoin().longValue();
assertEquals(expectedAmountLogged, amount.longValue());
}

@Test
void low_amount_release_request_rejected_after_lovell_value_in_weis() throws IOException {
@DisplayName("A rejected pegout due to low amount. Post lovell, the pegout value is preserved in weis. Both in the emitted event and the value refunded.")
void low_amount_release_request_rejected_after_lovell() throws IOException {
List<LogInfo> logInfo = new ArrayList<>();
eventLogger = spy(new BridgeEventLoggerImpl(
BRIDGE_CONSTANTS,
Expand Down Expand Up @@ -1346,7 +1358,8 @@ void low_amount_release_request_rejected_after_lovell_value_in_weis() throws IOE
}

@Test
void contract_caller_release_request_rejected_before_lovell_value_in_satoshis() throws IOException {
@DisplayName("A pegout from a contract is rejected. Pre lovell, the pegout value is rounded down to the nearest satoshi. Both in the emitted event and the value refunded.")
void contract_caller_release_request_rejected_before_lovell() throws IOException {
ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0L);

List<LogInfo> logInfo = new ArrayList<>();
Expand All @@ -1359,11 +1372,17 @@ void contract_caller_release_request_rejected_before_lovell_value_in_satoshis()
bridgeSupport = initBridgeSupport(eventLogger, arrowheadActivations);

co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(BRIDGE_CONSTANTS.getMinimumPegoutTxValue());
// Add some extra weis to the value, but less than 1 satoshi.
// To ensure that the pegout value is rounded down to fit in satoshis.
co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.valueOf(Denomination.satoshisToWeis(1).longValue());
co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(co.rsk.core.Coin.valueOf(1));
pegoutRequestValue = pegoutRequestValue.add(extraWeis);

bridgeSupport.releaseBtc(buildReleaseRskTx_fromContract(pegoutRequestValue));

RskAddress senderAddress = new RskAddress(SENDER.getAddress());

// No refund is made to a contract
verify(repository, never()).transfer(any(), any(), any());

assertEquals(0, provider.getReleaseRequestQueue().getEntries().size());
Expand All @@ -1381,11 +1400,15 @@ void contract_caller_release_request_rejected_before_lovell_value_in_satoshis()
assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData());

BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0];
assertEquals(pegoutRequestValue.toBitcoin().longValue(), amount.longValue());
// Pre lovell, the logged value should be rounded down to the nearest satoshi.
co.rsk.core.Coin expectedLoggedValue = pegoutRequestValue.subtract(extraWeis);
long expectedAmountLogged = expectedLoggedValue.toBitcoin().longValue();
assertEquals(expectedAmountLogged, amount.longValue());
}

@Test
void contract_caller_release_request_rejected_after_lovell_value_in_weis() throws IOException {
@DisplayName("A pegout from a contract is rejected. Post lovell, the pegout value is preserved in weis. Both in the emitted event and the value refunded.")
void contract_caller_release_request_rejected_after_lovell() throws IOException {
List<LogInfo> logInfo = new ArrayList<>();
eventLogger = spy(new BridgeEventLoggerImpl(
BRIDGE_CONSTANTS,
Expand All @@ -1396,11 +1419,17 @@ void contract_caller_release_request_rejected_after_lovell_value_in_weis() throw
bridgeSupport = initBridgeSupport(eventLogger, ACTIVATIONS_ALL);

co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(BRIDGE_CONSTANTS.getMinimumPegoutTxValue());
// Add some extra weis to the value, but less than 1 satoshi.
// To ensure that the pegout value is rounded down to fit in satoshis.
co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.valueOf(Denomination.satoshisToWeis(1).longValue());
co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(co.rsk.core.Coin.valueOf(1));
pegoutRequestValue = pegoutRequestValue.add(extraWeis);

bridgeSupport.releaseBtc(buildReleaseRskTx_fromContract(pegoutRequestValue));

RskAddress senderAddress = new RskAddress(SENDER.getAddress());

// No refund is made to a contract
verify(repository, never()).transfer(any(), any(), any());

assertEquals(0, provider.getReleaseRequestQueue().getEntries().size());
Expand All @@ -1422,7 +1451,8 @@ void contract_caller_release_request_rejected_after_lovell_value_in_weis() throw
}

@Test
void fee_above_value_release_request_rejected_before_lovell_value_in_satoshis() throws IOException {
@DisplayName("A pegout rejected due to high fees. Pre lovell, the pegout value is rounded down to the nearest satoshi. Both in the emitted event and the value refunded.")
void fee_above_value_release_request_rejected_before_lovell() throws IOException {
ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0L);

List<LogInfo> logInfo = new ArrayList<>();
Expand All @@ -1447,15 +1477,22 @@ void fee_above_value_release_request_rejected_before_lovell_value_in_satoshis()

Coin pegoutRequestValueWithGapAboveFee = minValueWithGapAboveFee.minus(Coin.SATOSHI);
co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(pegoutRequestValueWithGapAboveFee);
// Add some extra weis to the value, but less than 1 satoshi.
// To ensure that the pegout value is rounded down to fit in satoshis.
co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.valueOf(Denomination.satoshisToWeis(1).longValue());
co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(co.rsk.core.Coin.valueOf(1));
pegoutRequestValue = pegoutRequestValue.add(extraWeis);

bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue));

RskAddress senderAddress = new RskAddress(SENDER.getAddress());

// Pre lovell, the refund should be rounded down to the nearest satoshi.
co.rsk.core.Coin expectedRefundValue = pegoutRequestValue.subtract(extraWeis);
verify(repository, times(1)).transfer(
BRIDGE_ADDRESS,
senderAddress,
pegoutRequestValue
expectedRefundValue
);

assertEquals(0, provider.getReleaseRequestQueue().getEntries().size());
Expand All @@ -1472,12 +1509,15 @@ void fee_above_value_release_request_rejected_before_lovell_value_in_satoshis()
CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent();
assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData());

// Same case in the log, the value should be rounded down to the nearest satoshi.
BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0];
assertEquals(pegoutRequestValue.toBitcoin().longValue(), amount.longValue());
long expectedAmountLogged = expectedRefundValue.toBitcoin().longValue();
assertEquals(expectedAmountLogged, amount.longValue());
}

@Test
void fee_above_value_release_request_rejected_after_lovell_value_in_weis() throws IOException {
@DisplayName("A pegout rejected due to high fees. Post lovell, the pegout value is preserved in weis. Both in the emitted event and the value refunded.")
void fee_above_value_release_request_rejected_after_lovell() throws IOException {
List<LogInfo> logInfo = new ArrayList<>();
eventLogger = spy(new BridgeEventLoggerImpl(
BRIDGE_CONSTANTS,
Expand All @@ -1500,6 +1540,11 @@ void fee_above_value_release_request_rejected_after_lovell_value_in_weis() throw

Coin pegoutRequestValueWithGapAboveFee = minValueWithGapAboveFee.minus(Coin.SATOSHI);
co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(pegoutRequestValueWithGapAboveFee);
// Add some extra weis to the value, but less than 1 satoshi.
// To ensure that the pegout value is rounded down to fit in satoshis.
co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.valueOf(Denomination.satoshisToWeis(1).longValue());
co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(co.rsk.core.Coin.valueOf(1));
pegoutRequestValue = pegoutRequestValue.add(extraWeis);

bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue));

Expand Down

0 comments on commit 8e07881

Please sign in to comment.