diff --git a/rskj-core/src/main/java/co/rsk/peg/bitcoin/BitcoinUtils.java b/rskj-core/src/main/java/co/rsk/peg/bitcoin/BitcoinUtils.java index a347d3b41c..cfcfb56e9d 100644 --- a/rskj-core/src/main/java/co/rsk/peg/bitcoin/BitcoinUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/bitcoin/BitcoinUtils.java @@ -12,9 +12,9 @@ import org.slf4j.LoggerFactory; public class BitcoinUtils { - public static final byte WITNESS_COMMITMENT_LENGTH = 36; // 4 bytes for header, 32 for hash - public static final Sha256Hash WITNESS_RESERVED_VALUE = Sha256Hash.ZERO_HASH; protected static final byte[] WITNESS_COMMITMENT_HEADER = Hex.decode("aa21a9ed"); + protected static final int WITNESS_COMMITMENT_LENGTH = WITNESS_COMMITMENT_HEADER.length + Sha256Hash.LENGTH; + private static final int MINIMUM_WITNESS_COMMITMENT_SIZE = WITNESS_COMMITMENT_LENGTH + 2; // 1 extra by for OP_RETURN and another one for data length private static final Logger logger = LoggerFactory.getLogger(BitcoinUtils.class); private static final int FIRST_INPUT_INDEX = 0; @@ -90,7 +90,7 @@ public static Optional findWitnessCommitment(BtcTransaction tx) { for (TransactionOutput output : outputsReversed) { Script scriptPubKey = output.getScriptPubKey(); if (isWitnessCommitment(scriptPubKey)) { - Sha256Hash witnessCommitment = ScriptPattern.extractWitnessCommitmentHash(scriptPubKey); + Sha256Hash witnessCommitment = extractWitnessCommitmentHash(scriptPubKey); return Optional.of(witnessCommitment); } } @@ -99,7 +99,6 @@ public static Optional findWitnessCommitment(BtcTransaction tx) { } private static boolean isWitnessCommitment(Script scriptPubKey) { - final int MINIMUM_WITNESS_COMMITMENT_SIZE = 38; byte[] scriptPubKeyProgram = scriptPubKey.getProgram(); return scriptPubKeyProgram.length >= MINIMUM_WITNESS_COMMITMENT_SIZE @@ -115,4 +114,21 @@ private static boolean hasCommitmentStructure(byte[] scriptPubKeyProgram) { private static boolean hasWitnessCommitmentHeader(byte[] header) { return Arrays.equals(header, WITNESS_COMMITMENT_HEADER); } + + /** + * Retrieves the hash from a segwit commitment (in an output of the coinbase transaction). + */ + private static Sha256Hash extractWitnessCommitmentHash(Script scriptPubKey) { + byte[] scriptPubKeyProgram = scriptPubKey.getProgram(); + Preconditions.checkState(scriptPubKeyProgram.length >= MINIMUM_WITNESS_COMMITMENT_SIZE); + + final int WITNESS_COMMITMENT_HASH_START = 6; // 4 bytes for header + OP_RETURN + data length + byte[] witnessCommitmentHash = Arrays.copyOfRange( + scriptPubKeyProgram, + WITNESS_COMMITMENT_HASH_START, + MINIMUM_WITNESS_COMMITMENT_SIZE + ); + + return Sha256Hash.wrap(witnessCommitmentHash); + } } diff --git a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java index 1fae78e66a..9439cd27f4 100644 --- a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java +++ b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java @@ -14,6 +14,7 @@ import org.ethereum.util.ByteUtil; public class BitcoinTestUtils { + public static final Sha256Hash WITNESS_RESERVED_VALUE = Sha256Hash.ZERO_HASH; public static BtcECKey getBtcEcKeyFromSeed(String seed) { byte[] serializedSeed = HashUtil.keccak256(seed.getBytes(StandardCharsets.UTF_8)); @@ -215,7 +216,7 @@ public static BtcTransaction createCoinbaseTransactionWithWrongWitnessCommitment byte[] wrongWitnessCommitmentWithHeader = ByteUtil.merge( new byte[]{ScriptOpCodes.OP_RETURN}, new byte[]{ScriptOpCodes.OP_PUSHDATA1}, - new byte[]{BitcoinUtils.WITNESS_COMMITMENT_LENGTH}, + new byte[]{(byte) BitcoinUtils.WITNESS_COMMITMENT_LENGTH}, BitcoinUtils.WITNESS_COMMITMENT_HEADER, witnessCommitment.getBytes() ); @@ -230,7 +231,7 @@ private static BtcTransaction createCoinbaseTxWithWitnessReservedValue(NetworkPa BtcTransaction coinbaseTx = createCoinbaseTransaction(networkParameters); TransactionWitness txWitness = new TransactionWitness(1); - txWitness.setPush(0, BitcoinUtils.WITNESS_RESERVED_VALUE.getBytes()); + txWitness.setPush(0, WITNESS_RESERVED_VALUE.getBytes()); coinbaseTx.setWitness(0, txWitness); return coinbaseTx; diff --git a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java index 41997d8357..0f03d362af 100644 --- a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java @@ -33,7 +33,7 @@ private boolean isSigHashValid(Sha256Hash sigHash, List pubKeys, List< LinkedList keys = new LinkedList<>(pubKeys); LinkedList sigs = new LinkedList<>(signatures); - while (sigs.size() > 0){ + while (!sigs.isEmpty()){ BtcECKey pubKey = keys.pollFirst(); BtcECKey.ECDSASignature signature = sigs.getFirst(); if(pubKey.verify(sigHash, signature)){ @@ -272,7 +272,7 @@ void extractRedeemScriptFromInput_p2sh_pegin_v1() { assertFalse(btcTx.getInputs().isEmpty()); List scriptSigChunks = scriptSig.getChunks(); - Script expectedRedeemScript = new Script( scriptSigChunks.get(scriptSigChunks.size()- 1).data); + Script expectedRedeemScript = new Script(scriptSigChunks.get(scriptSigChunks.size()- 1).data); // Act Optional