Skip to content

Commit

Permalink
Merge pull request #2910 from rsksmart/mark-invalid-pegin-as-processed
Browse files Browse the repository at this point in the history
Mark invalid pegin as processed
  • Loading branch information
marcos-iov authored Jan 10, 2025
2 parents 53ca88d + bf15222 commit ac0df42
Show file tree
Hide file tree
Showing 13 changed files with 819 additions and 115 deletions.
99 changes: 62 additions & 37 deletions rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import static co.rsk.peg.ReleaseTransactionBuilder.BTC_TX_VERSION_2;
import static co.rsk.peg.bitcoin.BitcoinUtils.*;
import static co.rsk.peg.bitcoin.UtxoUtils.extractOutpointValues;
import static co.rsk.peg.pegin.RejectedPeginReason.INVALID_AMOUNT;
import static java.util.Objects.isNull;
import static org.ethereum.config.blockchain.upgrades.ConsensusRule.*;

Expand Down Expand Up @@ -503,48 +502,74 @@ protected void registerPegIn(
);

PeginProcessAction peginProcessAction = peginEvaluationResult.getPeginProcessAction();
if (peginProcessAction == PeginProcessAction.CAN_BE_REGISTERED) {
logger.debug("[{}] Peg-in is valid, going to register", METHOD_NAME);
executePegIn(btcTx, peginInformation, totalAmount);
} else {
Optional<RejectedPeginReason> rejectedPeginReasonOptional = peginEvaluationResult.getRejectedPeginReason();
if (rejectedPeginReasonOptional.isEmpty()) {
// This flow should never be reached. There should always be a rejected pegin reason.
String message = "Invalid state. No rejected reason was returned from evaluatePegin method";
logger.error("[{}}] {}", METHOD_NAME, message);
throw new IllegalStateException(message);
}

RejectedPeginReason rejectedPeginReason = rejectedPeginReasonOptional.get();
logger.debug("[{}] Rejected peg-in, reason {}", METHOD_NAME, rejectedPeginReason);
eventLogger.logRejectedPegin(btcTx, rejectedPeginReason);
if (peginProcessAction == PeginProcessAction.CAN_BE_REFUNDED) {
logger.debug("[{}] Refunding to address {} ", METHOD_NAME, peginInformation.getBtcRefundAddress());
generateRejectionRelease(btcTx, peginInformation.getBtcRefundAddress(), rskTxHash, totalAmount);
markTxAsProcessed(btcTx);
} else {
logger.debug("[{}] Unprocessable transaction {}.", METHOD_NAME, btcTx.getHash());
handleUnprocessableBtcTx(btcTx, peginInformation.getProtocolVersion(), rejectedPeginReason);
switch (peginProcessAction) {
case REGISTER -> {
logger.debug("[{}] Peg-in is valid, going to register", METHOD_NAME);
executePegIn(btcTx, peginInformation, totalAmount);
}
case REFUND -> handleRefundablePegin(btcTx, rskTxHash, peginEvaluationResult,
peginInformation.getBtcRefundAddress());
case NO_REFUND -> handleNonRefundablePegin(btcTx, peginInformation.getProtocolVersion(),
peginEvaluationResult);
}
}

private void handleUnprocessableBtcTx(
private void handleRefundablePegin(BtcTransaction btcTx, Keccak256 rskTxHash,
PeginEvaluationResult peginEvaluationResult, Address btcRefundAddress)
throws IOException {
RejectedPeginReason rejectedPeginReason = peginEvaluationResult.getRejectedPeginReason()
.orElseThrow(() -> {
// This flow should never be reached. There should always be a rejected pegin reason.
String message = "Invalid state. No rejected reason was returned for an invalid pegin.";
logger.error("[{handleRefundablePegin}] {}", message);
return new IllegalStateException(message);
});

logger.debug("[{handleRefundablePegin}] Rejected peg-in, reason {}", rejectedPeginReason);
eventLogger.logRejectedPegin(btcTx, rejectedPeginReason);

logger.debug("[{handleRefundablePegin}] Refunding to address {} ", btcRefundAddress);
Coin totalAmount = computeTotalAmountSent(btcTx);
generateRejectionRelease(btcTx, btcRefundAddress, rskTxHash,
totalAmount);
markTxAsProcessed(btcTx);
}

private void handleNonRefundablePegin(
BtcTransaction btcTx,
int protocolVersion,
RejectedPeginReason rejectedPeginReason
) {
UnrefundablePeginReason unrefundablePeginReason;
if (rejectedPeginReason == INVALID_AMOUNT) {
unrefundablePeginReason = UnrefundablePeginReason.INVALID_AMOUNT;
} else {
unrefundablePeginReason = protocolVersion == 1 ?
UnrefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET :
UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER;
}
PeginEvaluationResult peginEvaluationResult
) throws IOException {
RejectedPeginReason rejectedPeginReason = peginEvaluationResult.getRejectedPeginReason()
.orElseThrow(() -> {
// This flow should never be reached. There should always be a rejected pegin reason.
String message = "Invalid state. No rejected reason was returned for an invalid pegin.";
logger.error("[{handleNonRefundablePegin}] {}", message);
return new IllegalStateException(message);
});

logger.debug("[{handleNonRefundablePegin}] Rejected peg-in, reason {}",
rejectedPeginReason);
eventLogger.logRejectedPegin(btcTx, rejectedPeginReason);

NonRefundablePeginReason nonRefundablePeginReason = switch (rejectedPeginReason) {
case INVALID_AMOUNT -> NonRefundablePeginReason.INVALID_AMOUNT;
case LEGACY_PEGIN_UNDETERMINED_SENDER, PEGIN_V1_INVALID_PAYLOAD ->
protocolVersion == 1 ? NonRefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET
: NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER;
default -> throw new IllegalStateException("Unexpected value: " + rejectedPeginReason);
};

logger.debug("[handleNonRefundablePegin] Nonrefundable tx {}. Reason {}", btcTx.getHash(),
nonRefundablePeginReason);
eventLogger.logNonRefundablePegin(btcTx, nonRefundablePeginReason);

logger.debug("[handleUnprocessableBtcTx] Unprocessable tx {}. Reason {}", btcTx.getHash(), unrefundablePeginReason);
eventLogger.logUnrefundablePegin(btcTx, unrefundablePeginReason);
if (!activations.isActive(RSKIP459)) {
return;
}
// Since RSKIP459, rejected peg-ins should be marked as processed
markTxAsProcessed(btcTx);
}

/**
Expand Down Expand Up @@ -712,9 +737,9 @@ private void refundTxSender(

if (activations.isActive(ConsensusRule.RSKIP181)) {
if (peginInformation.getProtocolVersion() == 1) {
eventLogger.logUnrefundablePegin(btcTx, UnrefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET);
eventLogger.logNonRefundablePegin(btcTx, NonRefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET);
} else {
eventLogger.logUnrefundablePegin(btcTx, UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER);
eventLogger.logNonRefundablePegin(btcTx, NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER);
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions rskj-core/src/main/java/co/rsk/peg/PegUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ static PeginEvaluationResult evaluatePegin(

if(!allUTXOsToFedAreAboveMinimumPeginValue(btcTx, fedWallet, minimumPeginTxValue, activations)) {
logger.debug("[evaluatePegin] Peg-in contains at least one utxo below the minimum value");
return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_PROCESSED, INVALID_AMOUNT);
return new PeginEvaluationResult(PeginProcessAction.NO_REFUND, INVALID_AMOUNT);
}

try {
Expand All @@ -196,8 +196,8 @@ static PeginEvaluationResult evaluatePegin(
boolean hasRefundAddress = peginInformation.getBtcRefundAddress() != null;

PeginProcessAction peginProcessAction = hasRefundAddress ?
PeginProcessAction.CAN_BE_REFUNDED :
PeginProcessAction.CANNOT_BE_PROCESSED;
PeginProcessAction.REFUND :
PeginProcessAction.NO_REFUND;

return new PeginEvaluationResult(peginProcessAction, PEGIN_V1_INVALID_PAYLOAD);
}
Expand All @@ -207,7 +207,7 @@ static PeginEvaluationResult evaluatePegin(
case 0:
return evaluateLegacyPeginSender(peginInformation.getSenderBtcAddressType());
case 1:
return new PeginEvaluationResult(PeginProcessAction.CAN_BE_REGISTERED);
return new PeginEvaluationResult(PeginProcessAction.REGISTER);
default:
// This flow should never be reached.
String message = String.format("Invalid state. Unexpected pegin protocol %d", protocolVersion);
Expand All @@ -220,12 +220,12 @@ private static PeginEvaluationResult evaluateLegacyPeginSender(TxSenderAddressTy
switch (senderAddressType) {
case P2PKH:
case P2SHP2WPKH:
return new PeginEvaluationResult(PeginProcessAction.CAN_BE_REGISTERED);
return new PeginEvaluationResult(PeginProcessAction.REGISTER);
case P2SHMULTISIG:
case P2SHP2WSH:
return new PeginEvaluationResult(PeginProcessAction.CAN_BE_REFUNDED, LEGACY_PEGIN_MULTISIG_SENDER);
return new PeginEvaluationResult(PeginProcessAction.REFUND, LEGACY_PEGIN_MULTISIG_SENDER);
default:
return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_PROCESSED, LEGACY_PEGIN_UNDETERMINED_SENDER);
return new PeginEvaluationResult(PeginProcessAction.NO_REFUND, LEGACY_PEGIN_UNDETERMINED_SENDER);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package co.rsk.peg.pegin;

public enum PeginProcessAction {
CAN_BE_REGISTERED,
CAN_BE_REFUNDED,
CANNOT_BE_PROCESSED
REGISTER,
REFUND,
NO_REFUND
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ default void logRejectedPegin(BtcTransaction btcTx, RejectedPeginReason reason)
throw new UnsupportedOperationException();
}

default void logUnrefundablePegin(BtcTransaction btcTx, UnrefundablePeginReason reason) {
default void logNonRefundablePegin(BtcTransaction btcTx, NonRefundablePeginReason reason) {
throw new UnsupportedOperationException();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public void logRejectedPegin(BtcTransaction btcTx, RejectedPeginReason reason) {
}

@Override
public void logUnrefundablePegin(BtcTransaction btcTx, UnrefundablePeginReason reason) {
public void logNonRefundablePegin(BtcTransaction btcTx, NonRefundablePeginReason reason) {
CallTransaction.Function event = BridgeEvents.UNREFUNDABLE_PEGIN.getEvent();

byte[] btcTxHashSerialized = btcTx.getHash().getBytes();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package co.rsk.peg.utils;

public enum UnrefundablePeginReason {
public enum NonRefundablePeginReason {
LEGACY_PEGIN_UNDETERMINED_SENDER(1),
PEGIN_V1_REFUND_ADDRESS_NOT_SET(2),
INVALID_AMOUNT(3);

private final int value;

UnrefundablePeginReason(int value) {
NonRefundablePeginReason(int value) {
this.value = value;
}

Expand Down
Loading

0 comments on commit ac0df42

Please sign in to comment.