Skip to content

Commit

Permalink
Merge pull request #2791 from rsksmart/wip/fed-scripts-refactors-inte…
Browse files Browse the repository at this point in the history
…gration

Add support to RedeemScriptParser changes after refactoring
  • Loading branch information
josedahlquist authored Oct 18, 2024
2 parents 918a94e + 6846684 commit 94f6e1b
Show file tree
Hide file tree
Showing 21 changed files with 1,132 additions and 325 deletions.
8 changes: 0 additions & 8 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,6 @@
<sha256 value="c717c468bfc91536f1dbc0d98d6116a8e7c49fbaff643ef8710e7505cc450878" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="co.rsk.bitcoinj" name="bitcoinj-thin" version="0.14.4-rsk-15">
<artifact name="bitcoinj-thin-0.14.4-rsk-15.jar">
<sha256 value="871b008d5b148f066a6e4d46b154a96532e22b7b6faff6e28821fa4e7b078346" origin="Generated by Gradle"/>
</artifact>
<artifact name="bitcoinj-thin-0.14.4-rsk-15.pom">
<sha256 value="deda61ace1b697c488c8acddbc60fcc55be75df9097c8cd2dad87f8c6afa21f2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml" name="oss-parent" version="38">
<artifact name="oss-parent-38.pom">
<sha256 value="c83f8f45dfdca8d0b6b3661c60b3f84780f671b12e06f91ad5d1c1a1d1f966e8" origin="Generated by Gradle"/>
Expand Down
2 changes: 1 addition & 1 deletion rskj-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ ext {
jaxwsRtVer : '2.3.5',
picocliVer : '4.6.3',

bitcoinjThinVer: '0.14.4-rsk-15',
bitcoinjThinVer: '0.14.4-rsk-16-SNAPSHOT',
rskjNativeVer: '1.3.0',
]

Expand Down
23 changes: 12 additions & 11 deletions rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ private boolean cannotProcessNextBlock(StoredBlock previousBlock) {
* Get the wallet for the currently active federation
* @return A BTC wallet for the currently active federation
*
* @param shouldConsiderFlyoverUTXOs
* @param shouldConsiderFlyoverUTXOs Whether to consider flyover UTXOs
*/
public Wallet getActiveFederationWallet(boolean shouldConsiderFlyoverUTXOs) {
Federation federation = getActiveFederation();
Expand All @@ -294,7 +294,7 @@ public Wallet getActiveFederationWallet(boolean shouldConsiderFlyoverUTXOs) {
* or null if there's currently no retiring federation
* @return A BTC wallet for the currently active federation
*
* @param shouldConsiderFlyoverUTXOs
* @param shouldConsiderFlyoverUTXOs Whether to consider flyover UTXOs
*/
protected Wallet getRetiringFederationWallet(boolean shouldConsiderFlyoverUTXOs) {
List<UTXO> retiringFederationBtcUTXOs = federationSupport.getRetiringFederationBtcUTXOs();
Expand Down Expand Up @@ -351,8 +351,8 @@ public Wallet getNoSpendWalletForLiveFederations(boolean isFlyoverCompatible) {
* @param btcTxSerialized The raw BTC tx
* @param height The height of the BTC block that contains the tx
* @param pmtSerialized The raw partial Merkle tree
* @throws BlockStoreException
* @throws IOException
* @throws BlockStoreException If there's an error while executing validations
* @throws IOException If there's an error while processing the tx
*/
public void registerBtcTransaction(
Transaction rskTx,
Expand Down Expand Up @@ -804,7 +804,7 @@ private void saveNewUTXOs(BtcTransaction btcTx) {
* The funds will be sent to the bitcoin address controlled by the private key that signed the rsk tx.
* The amount sent to the bridge in this tx will be the amount sent in the btc network minus fees.
* @param rskTx The rsk tx being executed.
* @throws IOException
* @throws IOException If there's an error while processing the release request.
*/
public void releaseBtc(Transaction rskTx) throws IOException {
final co.rsk.core.Coin pegoutValueInWeis = rskTx.getValue();
Expand Down Expand Up @@ -866,7 +866,7 @@ private void emitRejectEvent(Coin value, RskAddress senderAddress, RejectedPegou
*
* @param destinationAddress the destination BTC address.
* @param value the amount of BTC to release.
* @throws IOException
* @throws IOException if there's an error while processing the request.
*/
private void requestRelease(Address destinationAddress, Coin value, Transaction rskTx) throws IOException {
Optional<RejectedPegoutReason> optionalRejectedPegoutReason = Optional.empty();
Expand Down Expand Up @@ -2431,17 +2431,18 @@ protected FlyoverFederationInformation createFlyoverFederationInformation(Keccak
}

protected FlyoverFederationInformation createFlyoverFederationInformation(Keccak256 flyoverDerivationHash, Federation federation) {
Script flyoverScript = FastBridgeRedeemScriptParser.createMultiSigFastBridgeRedeemScript(
federation.getRedeemScript(),
Sha256Hash.wrap(flyoverDerivationHash.getBytes())
Script federationRedeemScript = federation.getRedeemScript();
Script flyoverRedeemScript = FlyoverRedeemScriptBuilderImpl.builder().of(
flyoverDerivationHash,
federationRedeemScript
);

Script flyoverScriptHash = ScriptBuilder.createP2SHOutputScript(flyoverScript);
Script flyoverP2shOutputScript = ScriptBuilder.createP2SHOutputScript(flyoverRedeemScript);

return new FlyoverFederationInformation(
flyoverDerivationHash,
federation.getP2SHScript().getPubKeyHash(),
flyoverScriptHash.getPubKeyHash()
flyoverP2shOutputScript.getPubKeyHash()
);
}

Expand Down
32 changes: 12 additions & 20 deletions rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

import co.rsk.bitcoinj.core.*;
import co.rsk.bitcoinj.crypto.TransactionSignature;
import co.rsk.bitcoinj.script.RedeemScriptParser;
import co.rsk.bitcoinj.script.RedeemScriptParser.MultiSigType;
import co.rsk.bitcoinj.script.RedeemScriptParserFactory;
import co.rsk.bitcoinj.script.Script;
import co.rsk.bitcoinj.script.ScriptChunk;
Expand Down Expand Up @@ -319,20 +317,14 @@ public static int countMissingSignatures(Context btcContext, BtcTransaction btcT
TransactionInput input = btcTx.getInput(0);
Script scriptSig = input.getScriptSig();
List<ScriptChunk> chunks = scriptSig.getChunks();
Script redeemScript = new Script(chunks.get(chunks.size() - 1).data);
RedeemScriptParser parser = RedeemScriptParserFactory.get(redeemScript.getChunks());
MultiSigType multiSigType;

int lastChunk;
Script redeemScript = new Script(chunks.get(chunks.size() - 1).data);

multiSigType = parser.getMultiSigType();

if (multiSigType == MultiSigType.STANDARD_MULTISIG ||
multiSigType == MultiSigType.FAST_BRIDGE_MULTISIG
) {
lastChunk = chunks.size() - 1;
} else {
if (isErpType(redeemScript)) {
lastChunk = chunks.size() - 2;
} else {
lastChunk = chunks.size() - 1;
}

for (int i = 1; i < lastChunk; i++) {
Expand All @@ -344,6 +336,11 @@ public static int countMissingSignatures(Context btcContext, BtcTransaction btcT
return unsigned;
}

private static boolean isErpType(Script redeemScript) {
List<ScriptChunk> redeemScriptChunks = redeemScript.getChunks();
return RedeemScriptParserFactory.get(redeemScriptChunks).hasErpFormat();
}

/**
* Checks whether a btc tx has been signed by the required number of federators.
* @param btcContext Btc context
Expand All @@ -357,23 +354,18 @@ public static boolean hasEnoughSignatures(Context btcContext, BtcTransaction btc
Script scriptSig;
List<ScriptChunk> chunks;
Script redeemScript;
RedeemScriptParser parser;
MultiSigType multiSigType;

int lastChunk;
for (TransactionInput input : btcTx.getInputs()) {
scriptSig = input.getScriptSig();
chunks = scriptSig.getChunks();
redeemScript = new Script(chunks.get(chunks.size() - 1).data);
parser = RedeemScriptParserFactory.get(redeemScript.getChunks());
multiSigType = parser.getMultiSigType();

if (multiSigType == MultiSigType.STANDARD_MULTISIG ||
multiSigType == MultiSigType.FAST_BRIDGE_MULTISIG
if (isErpType(redeemScript)
) {
lastChunk = chunks.size() - 1;
} else {
lastChunk = chunks.size() - 2;
} else {
lastChunk = chunks.size() - 1;
}

for (int i = 1; i < lastChunk; i++) {
Expand Down
31 changes: 5 additions & 26 deletions rskj-core/src/main/java/co/rsk/peg/FlyoverCompatibleBtcWallet.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package co.rsk.peg;

import co.rsk.bitcoinj.core.Context;
import co.rsk.bitcoinj.core.Sha256Hash;
import co.rsk.bitcoinj.script.FastBridgeErpRedeemScriptParser;
import co.rsk.bitcoinj.script.FastBridgeRedeemScriptParser;
import co.rsk.bitcoinj.script.RedeemScriptParser;
import co.rsk.bitcoinj.script.RedeemScriptParser.MultiSigType;
import co.rsk.bitcoinj.script.RedeemScriptParserFactory;
import co.rsk.bitcoinj.script.Script;
import co.rsk.bitcoinj.wallet.RedeemData;
import co.rsk.peg.bitcoin.FlyoverRedeemScriptBuilderImpl;
import co.rsk.peg.federation.Federation;
import co.rsk.peg.flyover.FlyoverFederationInformation;
import java.util.List;
Expand Down Expand Up @@ -44,26 +39,10 @@ public RedeemData findRedeemDataFromScriptHash(byte[] payToScriptHash) {
Federation destinationFederationInstance = destinationFederation.get();
Script fedRedeemScript = destinationFederationInstance.getRedeemScript();

RedeemScriptParser parser = RedeemScriptParserFactory.get(fedRedeemScript.getChunks());
Script flyoverRedeemScript;

if (parser.getMultiSigType() == MultiSigType.ERP_FED) {
flyoverRedeemScript = FastBridgeErpRedeemScriptParser.createFastBridgeErpRedeemScript(
fedRedeemScript,
Sha256Hash.wrap(flyoverFederationInformationInstance
.getDerivationHash()
.getBytes()
)
);
} else {
flyoverRedeemScript = FastBridgeRedeemScriptParser.createMultiSigFastBridgeRedeemScript(
fedRedeemScript,
Sha256Hash.wrap(flyoverFederationInformationInstance
.getDerivationHash()
.getBytes()
)
);
}
Script flyoverRedeemScript = FlyoverRedeemScriptBuilderImpl.builder().of(
flyoverFederationInformationInstance.getDerivationHash(),
fedRedeemScript
);

return RedeemData.of(destinationFederationInstance.getBtcPublicKeys(), flyoverRedeemScript);
}
Expand Down
35 changes: 14 additions & 21 deletions rskj-core/src/main/java/co/rsk/peg/PegUtilsLegacy.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,25 @@ protected static boolean isPegOutTx(BtcTransaction btcTx, ActivationConfig.ForBl
int inputsSize = btcTx.getInputs().size();
for (int i = 0; i < inputsSize; i++) {
TransactionInput txInput = btcTx.getInput(i);
Optional<Script> redeemScriptOptional = BitcoinUtils.extractRedeemScriptFromInput(btcTx.getInput(i));
Optional<Script> redeemScriptOptional = BitcoinUtils.extractRedeemScriptFromInput(txInput);
if (!redeemScriptOptional.isPresent()) {
continue;
}

Script redeemScript = redeemScriptOptional.get();
List<ScriptChunk> redeemScriptChunks = redeemScriptOptional.get().getChunks();
if (activations.isActive(ConsensusRule.RSKIP201)) {
// Extract standard redeem script since the registered utxo could be from a fast bridge or erp federation
RedeemScriptParser redeemScriptParser = RedeemScriptParserFactory.get(txInput.getScriptSig().getChunks());
// Extract standard redeem script chunks since the registered utxo could be from a fast bridge or erp federation
try {
redeemScript = redeemScriptParser.extractStandardRedeemScript();
RedeemScriptParser redeemScriptParser = RedeemScriptParserFactory.get(redeemScriptChunks);
redeemScriptChunks = redeemScriptParser.extractStandardRedeemScriptChunks();
} catch (ScriptException e) {
logger.debug("[isPegOutTx] There is no redeem script", e);
// There is no redeem script
continue;
}
}

Script redeemScript = new ScriptBuilder().addChunks(redeemScriptChunks).build();
Script outputScript = ScriptBuilder.createP2SHOutputScript(redeemScript);
if (Arrays.stream(fedStandardP2shScripts).anyMatch(federationPayScript -> federationPayScript.equals(outputScript))) {
return true;
Expand Down Expand Up @@ -204,25 +205,17 @@ protected static boolean isValidPegInTx(
return false;
}

TransactionInput txInput = tx.getInput(i);
Optional<Script> redeemScriptOptional = BitcoinUtils.extractRedeemScriptFromInput(txInput);
// Check if the registered utxo is not change from an utxo spent from either a fast bridge federation,
// erp federation, or even a retired fast bridge or erp federation
if (activations.isActive(ConsensusRule.RSKIP201)) {
RedeemScriptParser redeemScriptParser = RedeemScriptParserFactory.get(tx.getInput(index).getScriptSig().getChunks());
if (activations.isActive(ConsensusRule.RSKIP201) && redeemScriptOptional.isPresent()) {
try {
// Consider transactions that have an input with a redeem script of type P2SH ERP FED
// to be "future transactions" that should not be pegins. These are gonna be considered pegouts.
// This is only for backwards compatibility reasons. As soon as RSKIP353 activates,
// pegins to the new federation should be valid again.
// There's no reason for someone to send an actual pegin of this type before the new fed is active.
// TODO: Remove this if block after RSKIP353 activation
if (!activations.isActive(ConsensusRule.RSKIP353) &&
(redeemScriptParser.getMultiSigType() == RedeemScriptParser.MultiSigType.P2SH_ERP_FED ||
redeemScriptParser.getMultiSigType() == RedeemScriptParser.MultiSigType.FAST_BRIDGE_P2SH_ERP_FED)) {
String message = "Tried to register a transaction with a P2SH ERP federation redeem script before RSKIP353 activation";
logger.warn("[isValidPegInTx] {}", message);
throw new ScriptException(message);
}
Script inputStandardRedeemScript = redeemScriptParser.extractStandardRedeemScript();
List<ScriptChunk> redeemScriptChunks = redeemScriptOptional.get().getChunks();
RedeemScriptParser redeemScriptParser = RedeemScriptParserFactory.get(redeemScriptChunks);

List<ScriptChunk> inputStandardRedeemScriptChunks = redeemScriptParser.extractStandardRedeemScriptChunks();
Script inputStandardRedeemScript = new ScriptBuilder().addChunks(inputStandardRedeemScriptChunks).build();
if (activeFederations.stream().anyMatch(federation -> getFederationStandardRedeemScript(federation).equals(inputStandardRedeemScript))) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package co.rsk.peg.bitcoin;

import static co.rsk.peg.bitcoin.RedeemScriptCreationException.Reason.INVALID_FLYOVER_DERIVATION_HASH;
import static co.rsk.peg.bitcoin.RedeemScriptCreationException.Reason.INVALID_INTERNAL_REDEEM_SCRIPTS;
import static java.util.Objects.isNull;

import co.rsk.bitcoinj.script.RedeemScriptParserFactory;
import co.rsk.bitcoinj.script.Script;
import co.rsk.bitcoinj.script.ScriptBuilder;
import co.rsk.bitcoinj.script.ScriptOpCodes;
Expand All @@ -22,6 +24,7 @@ public static FlyoverRedeemScriptBuilderImpl builder() {
@Override
public Script of(Keccak256 flyoverDerivationHash, Script redeemScript) {
validateFlyoverDerivationHash(flyoverDerivationHash);
validateInternalRedeemScript(redeemScript);

ScriptBuilder scriptBuilder = new ScriptBuilder();
byte[] flyoverDerivationHashSerialized = flyoverDerivationHash.getBytes();
Expand All @@ -40,4 +43,21 @@ private void validateFlyoverDerivationHash(Keccak256 flyoverDerivationHash) {
throw new RedeemScriptCreationException(message, INVALID_FLYOVER_DERIVATION_HASH);
}
}

private void validateInternalRedeemScript(Script internalRedeemScript) {
if (isNull(internalRedeemScript)) {
String message = "Provided redeem script is null.";
logger.warn("[validateRedeemScript] {}", message);
throw new RedeemScriptCreationException(message, INVALID_INTERNAL_REDEEM_SCRIPTS);
}

try {
// Check it can be parsed, so it has a valid structure
RedeemScriptParserFactory.get(internalRedeemScript.getChunks());
} catch (Exception e) {
String message = "Provided redeem script has an invalid structure.";
logger.warn("[validateRedeemScript] {}", message);
throw new RedeemScriptCreationException(message, INVALID_INTERNAL_REDEEM_SCRIPTS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public long getActivationDelay() {
public Script getDefaultRedeemScript() {
if (defaultRedeemScript == null) {
RedeemScriptParser redeemScriptParser = getRedeemScriptParser();
defaultRedeemScript = redeemScriptParser.extractStandardRedeemScript();
List<ScriptChunk> defaultRedeemScriptChunks = redeemScriptParser.extractStandardRedeemScriptChunks();
defaultRedeemScript = new ScriptBuilder().addChunks(defaultRedeemScriptChunks).build();
}
return defaultRedeemScript;
}
Expand Down
Loading

0 comments on commit 94f6e1b

Please sign in to comment.