Skip to content

Commit

Permalink
Create new methods to handle btc tx deserialization without inputs to…
Browse files Browse the repository at this point in the history
… avoid passing boolean
  • Loading branch information
julia-zack committed Sep 17, 2024
1 parent 729776e commit cc7bea6
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 55 deletions.
93 changes: 50 additions & 43 deletions rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,34 +61,51 @@ private BridgeSerializationUtils() {
throw new IllegalAccessError("Utility class, do not instantiate it");
}

public static byte[] serializeRskTxHash(Keccak256 rskTxHash) {
return RLP.encodeElement(rskTxHash.getBytes());
}

private static Keccak256 deserializeRskTxHashFromRLPData(byte[] rlpData) {
return new Keccak256(rlpData);
}

public static byte[] serializeBtcTransaction(BtcTransaction btcTransaction) {
return RLP.encodeElement(btcTransaction.bitcoinSerialize());
}

public static BtcTransaction deserializeBtcTransaction(byte[] data, NetworkParameters networkParameters) {
public static BtcTransaction deserializeBtcTransaction(byte[] data, NetworkParameters networkParameters, boolean txHasInputs) {
if (data == null || data.length == 0) {
return null;
}

RLPElement rlpElement = RLP.decode2(data).get(0);
byte[] rawTx = rlpElement.getRLPData();
byte[] rlpData = RLP.decode2(data).get(0).getRLPData();
return deserializeBtcTransactionFromRLPData(rlpData, networkParameters, txHasInputs);
}

private static BtcTransaction deserializeBtcTransactionFromRLPData(byte[] rlpData, NetworkParameters networkParameters, boolean txHasInputs) {
if (!txHasInputs) {
BtcTransaction tx = new BtcTransaction(networkParameters);
tx.parseNoInputs(rlpData);
return tx;
}

return new BtcTransaction(networkParameters, rlpData);
}

return new BtcTransaction(networkParameters, rawTx);
public static BtcTransaction deserializeSvpFundTx(byte[] data, NetworkParameters networkParameters) {
return deserializeBtcTransaction(data, networkParameters, true);
}

public static byte[] serializeRskTxWaitingForSignatures(
Map.Entry<Keccak256, BtcTransaction> rskTxWaitingForSignaturesEntry) {
byte[][] serializedRskTxWaitingForSignaturesEntry =
serializeRskTxWaitingForSignaturesEntry(rskTxWaitingForSignaturesEntry);
public static byte[] serializeRskTxWaitingForSignatures(Map.Entry<Keccak256, BtcTransaction> rskTxWaitingForSignaturesEntry) {
byte[][] serializedRskTxWaitingForSignaturesEntry = serializeRskTxWaitingForSignaturesEntry(rskTxWaitingForSignaturesEntry);
return RLP.encodeList(serializedRskTxWaitingForSignaturesEntry);
}

public static byte[] serializeRskTxsWaitingForSignatures(
SortedMap<Keccak256, BtcTransaction> rskTxWaitingForSignaturesMap) {
public static byte[] serializeRskTxsWaitingForSignatures(SortedMap<Keccak256, BtcTransaction> rskTxWaitingForSignaturesMap) {
int numberOfRskTxsWaitingForSignatures = rskTxWaitingForSignaturesMap.size();
byte[][] serializedRskTxWaitingForSignaturesMap = new byte[numberOfRskTxsWaitingForSignatures * 2][];
int n = 0;

int n = 0;
for (Map.Entry<Keccak256, BtcTransaction> rskTxWaitingForSignaturesEntry : rskTxWaitingForSignaturesMap.entrySet()) {
byte[][] serializedRskTxWaitingForSignaturesEntry = serializeRskTxWaitingForSignaturesEntry(rskTxWaitingForSignaturesEntry);
serializedRskTxWaitingForSignaturesMap[n++] = serializedRskTxWaitingForSignaturesEntry[0];
Expand All @@ -98,28 +115,23 @@ public static byte[] serializeRskTxsWaitingForSignatures(
return RLP.encodeList(serializedRskTxWaitingForSignaturesMap);
}

private static byte[][] serializeRskTxWaitingForSignaturesEntry(
Map.Entry<Keccak256, BtcTransaction> rskTxWaitingForSignaturesEntry) {
byte[] serializedRskTxWaitingForSignaturesEntryKey =
RLP.encodeElement(rskTxWaitingForSignaturesEntry.getKey().getBytes());
byte[] serializedRskTxWaitingForSignaturesEntryValue =
RLP.encodeElement(rskTxWaitingForSignaturesEntry.getValue().bitcoinSerialize());
private static byte[][] serializeRskTxWaitingForSignaturesEntry(Map.Entry<Keccak256, BtcTransaction> rskTxWaitingForSignaturesEntry) {
byte[] serializedRskTxWaitingForSignaturesEntryKey = serializeRskTxHash(rskTxWaitingForSignaturesEntry.getKey());
byte[] serializedRskTxWaitingForSignaturesEntryValue = serializeBtcTransaction(rskTxWaitingForSignaturesEntry.getValue());

return new byte[][] { serializedRskTxWaitingForSignaturesEntryKey, serializedRskTxWaitingForSignaturesEntryValue };
}

public static Map.Entry<Keccak256, BtcTransaction> deserializeRskTxWaitingForSignatures(
byte[] data, NetworkParameters networkParameters, boolean noInputsTxs) {
public static Map.Entry<Keccak256, BtcTransaction> deserializeRskTxWaitingForSignatures(byte[] data, NetworkParameters networkParameters) {
if (data == null || data.length == 0) {
return new AbstractMap.SimpleEntry<>(null, null);
}

RLPList rlpList = (RLPList) RLP.decode2(data).get(0);

return deserializeRskTxWaitingForSignaturesEntry(rlpList, 0, networkParameters, noInputsTxs);
return deserializeRskTxWaitingForSignaturesEntry(rlpList, 0, networkParameters);
}

public static SortedMap<Keccak256, BtcTransaction> deserializeRskTxsWaitingForSignatures(
byte[] data, NetworkParameters networkParameters, boolean noInputsTxs) {
public static SortedMap<Keccak256, BtcTransaction> deserializeRskTxsWaitingForSignatures(byte[] data, NetworkParameters networkParameters) {
SortedMap<Keccak256, BtcTransaction> rskTxsWaitingForSignaturesMap = new TreeMap<>();

if (data == null || data.length == 0) {
Expand All @@ -131,28 +143,22 @@ public static SortedMap<Keccak256, BtcTransaction> deserializeRskTxsWaitingForSi

for (int k = 0; k < numberOfRskTxsWaitingForSignatures; k++) {
Map.Entry<Keccak256, BtcTransaction> rskTxWaitingForSignaturesEntry =
deserializeRskTxWaitingForSignaturesEntry(rlpList, k, networkParameters, noInputsTxs);
deserializeRskTxWaitingForSignaturesEntry(rlpList, k, networkParameters);
rskTxsWaitingForSignaturesMap.put(
rskTxWaitingForSignaturesEntry.getKey(), rskTxWaitingForSignaturesEntry.getValue());
}

return rskTxsWaitingForSignaturesMap;
}

private static Map.Entry<Keccak256, BtcTransaction> deserializeRskTxWaitingForSignaturesEntry(
RLPList rlpList, int index, NetworkParameters networkParameters, boolean noInputsTxs) {
Keccak256 rskTxHash = new Keccak256(rlpList.get(index * 2).getRLPData());
byte[] payload = rlpList.get(index * 2 + 1).getRLPData();
BtcTransaction tx;

if (noInputsTxs) {
tx = new BtcTransaction(networkParameters);
tx.parseNoInputs(payload);
} else {
tx = new BtcTransaction(networkParameters, payload);
}
private static Map.Entry<Keccak256, BtcTransaction> deserializeRskTxWaitingForSignaturesEntry(RLPList rlpList, int index, NetworkParameters networkParameters) {
byte[] rskTxHashData = rlpList.get(index * 2).getRLPData();
Keccak256 rskTxHash = deserializeRskTxHashFromRLPData(rskTxHashData);

return new AbstractMap.SimpleEntry<>(rskTxHash, tx);
byte[] btcTxData = rlpList.get(index * 2 + 1).getRLPData();
BtcTransaction btcTx = deserializeBtcTransactionFromRLPData(btcTxData, networkParameters, true);

return new AbstractMap.SimpleEntry<>(rskTxHash, btcTx);
}

public static byte[] serializeUTXOList(List<UTXO> list) {
Expand Down Expand Up @@ -626,7 +632,8 @@ private static List<ReleaseRequestQueue.Entry> deserializeReleaseRequestQueueWit
byte[] addressBytes = rlpList.get(k * 3).getRLPData();
Address address = new Address(networkParameters, addressBytes);
long amount = BigIntegers.fromUnsignedByteArray(rlpList.get(k * 3 + 1).getRLPData()).longValue();
Keccak256 txHash = new Keccak256(rlpList.get(k * 3 + 2).getRLPData());

Keccak256 txHash = deserializeRskTxHashFromRLPData(rlpList.get(k * 3 + 2).getRLPData());

entries.add(new ReleaseRequestQueue.Entry(address, Coin.valueOf(amount), txHash));
}
Expand All @@ -650,7 +657,7 @@ public static byte[] serializePegoutsWaitingForConfirmations(PegoutsWaitingForCo
int n = 0;

for (PegoutsWaitingForConfirmations.Entry entry : entries) {
bytes[n++] = RLP.encodeElement(entry.getBtcTransaction().bitcoinSerialize());
bytes[n++] = serializeBtcTransaction(entry.getBtcTransaction());
bytes[n++] = RLP.encodeBigInteger(BigInteger.valueOf(entry.getPegoutCreationRskBlockNumber()));
}

Expand All @@ -665,9 +672,9 @@ public static byte[] serializePegoutsWaitingForConfirmationsWithTxHash(PegoutsWa
int n = 0;

for (PegoutsWaitingForConfirmations.Entry entry : entries) {
bytes[n++] = RLP.encodeElement(entry.getBtcTransaction().bitcoinSerialize());
bytes[n++] = serializeBtcTransaction(entry.getBtcTransaction());
bytes[n++] = RLP.encodeBigInteger(BigInteger.valueOf(entry.getPegoutCreationRskBlockNumber()));
bytes[n++] = RLP.encodeElement(entry.getPegoutCreationRskTxHash().getBytes());
bytes[n++] = serializeRskTxHash(entry.getPegoutCreationRskTxHash());
}

return RLP.encodeList(bytes);
Expand Down Expand Up @@ -719,7 +726,7 @@ private static PegoutsWaitingForConfirmations deserializePegoutWaitingForConfirm
BtcTransaction tx = new BtcTransaction(networkParameters, txPayload);

long height = BigIntegers.fromUnsignedByteArray(rlpList.get(k * 3 + 1).getRLPData()).longValue();
Keccak256 rskTxHash = new Keccak256(rlpList.get(k * 3 + 2).getRLPData());
Keccak256 rskTxHash = deserializeRskTxHashFromRLPData(rlpList.get(k * 3 + 2).getRLPData());

entries.add(new PegoutsWaitingForConfirmations.Entry(tx, height, rskTxHash));
}
Expand Down Expand Up @@ -808,7 +815,7 @@ public static FlyoverFederationInformation deserializeFlyoverFederationInformati
if (rlpList.size() != 2) {
throw new RuntimeException(String.format("Invalid serialized Fast Bridge Federation: expected 2 value but got %d", rlpList.size()));
}
Keccak256 derivationHash = new Keccak256(rlpList.get(0).getRLPData());
Keccak256 derivationHash = deserializeRskTxHashFromRLPData(rlpList.get(0).getRLPData());
byte[] federationP2SH = rlpList.get(1).getRLPData();

return new FlyoverFederationInformation(derivationHash, federationP2SH, flyoverScriptHash);
Expand Down
2 changes: 1 addition & 1 deletion rskj-core/src/main/java/co/rsk/peg/BridgeState.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public static BridgeState create(BridgeConstants bridgeConstants, byte[] data, @
byte[] btcUTXOsBytes = rlpList.get(1).getRLPData();
List<UTXO> btcUTXOs = BridgeSerializationUtils.deserializeUTXOList(btcUTXOsBytes);
byte[] rskTxsWaitingForSignaturesBytes = rlpList.get(2).getRLPData();
SortedMap<Keccak256, BtcTransaction> rskTxsWaitingForSignatures = BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(rskTxsWaitingForSignaturesBytes, bridgeConstants.getBtcParams(), false);
SortedMap<Keccak256, BtcTransaction> rskTxsWaitingForSignatures = BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(rskTxsWaitingForSignaturesBytes, bridgeConstants.getBtcParams());
byte[] releaseRequestQueueBytes = rlpList.get(3).getRLPData();
ReleaseRequestQueue releaseRequestQueue = new ReleaseRequestQueue(BridgeSerializationUtils.deserializeReleaseRequestQueue(releaseRequestQueueBytes, bridgeConstants.getBtcParams(), shouldUsePapyrusEncoding(activations)));
byte[] pegoutsWaitingForConfirmationsBytes = rlpList.get(4).getRLPData();
Expand Down
4 changes: 2 additions & 2 deletions rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ public SortedMap<Keccak256, BtcTransaction> getPegoutsWaitingForSignatures() thr

pegoutsWaitingForSignatures = getFromRepository(
PEGOUTS_WAITING_FOR_SIGNATURES,
data -> BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(data, networkParameters, false)
data -> BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(data, networkParameters)
);
return pegoutsWaitingForSignatures;
}
Expand Down Expand Up @@ -562,7 +562,7 @@ public Optional<BtcTransaction> getSvpFundTxSigned() {
}

svpFundTxSigned = safeGetFromRepository(SVP_FUND_TX_SIGNED,
data -> BridgeSerializationUtils.deserializeBtcTransaction(data, networkParameters));
data -> BridgeSerializationUtils.deserializeSvpFundTx(data, networkParameters));
return Optional.ofNullable(svpFundTxSigned);
}

Expand Down
2 changes: 1 addition & 1 deletion rskj-core/src/main/java/co/rsk/peg/StateForFederator.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public StateForFederator(byte[] rlpData, NetworkParameters parameters) {
RLPList rlpList = (RLPList) RLP.decode2(rlpData).get(0);
byte[] encodedWaitingForSign = rlpList.get(0).getRLPData();

this.rskTxsWaitingForSignatures = BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(encodedWaitingForSign, parameters, false);
this.rskTxsWaitingForSignatures = BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(encodedWaitingForSign, parameters);
}

public SortedMap<Keccak256, BtcTransaction> getRskTxsWaitingForSignatures() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class BridgeSerializationUtilsTest {
private static final Address OTHER_ADDRESS = BitcoinTestUtils.createP2PKHAddress(NETWORK_PARAMETERS, "second");

@Test
void serializeAndDeserializeBtcTransaction_whenValidData_shouldReturnEqualResults() {
void serializeAndDeserializeBtcTransaction_withValidDataAndInputs_shouldReturnEqualResults() {
// Arrange
BtcTransaction fundTx = new BtcTransaction(NETWORK_PARAMETERS);
fundTx.addOutput(Coin.FIFTY_COINS, ADDRESS);
Expand All @@ -101,20 +101,75 @@ void serializeAndDeserializeBtcTransaction_whenValidData_shouldReturnEqualResult

// Act
byte[] serializedBtcTransaction = BridgeSerializationUtils.serializeBtcTransaction(btcTx);
BtcTransaction deserializedBtcTransaction = BridgeSerializationUtils.deserializeBtcTransaction(serializedBtcTransaction, NETWORK_PARAMETERS);
BtcTransaction deserializedBtcTransaction = BridgeSerializationUtils.deserializeBtcTransaction(serializedBtcTransaction, NETWORK_PARAMETERS, true);

// Assert
assertNotNull(serializedBtcTransaction);
assertNotNull(deserializedBtcTransaction);
assertEquals(btcTx, deserializedBtcTransaction);
}

@Test
void serializeAndDeserializeBtcTransaction_withValidDataAndWithoutInputs_shouldReturnEqualResults() {
// Arrange
BtcTransaction fundTx = new BtcTransaction(NETWORK_PARAMETERS);
fundTx.addOutput(Coin.FIFTY_COINS, ADDRESS);
fundTx.addOutput(Coin.FIFTY_COINS, OTHER_ADDRESS);

BtcTransaction btcTx = new BtcTransaction(NETWORK_PARAMETERS);
btcTx.addOutput(Coin.COIN, OTHER_ADDRESS);

// Act
byte[] serializedBtcTransaction = BridgeSerializationUtils.serializeBtcTransaction(btcTx);
BtcTransaction deserializedBtcTransaction = BridgeSerializationUtils.deserializeBtcTransaction(serializedBtcTransaction, NETWORK_PARAMETERS, false);

// Assert
assertNotNull(serializedBtcTransaction);
assertNotNull(deserializedBtcTransaction);
assertEquals(btcTx, deserializedBtcTransaction);
}

@ParameterizedTest
@NullSource
@EmptySource
void deserializeBtcTransaction_withInvalidData_shouldReturnNull(byte[] data) {
// Act
BtcTransaction deserializedTxWithInputs = BridgeSerializationUtils.deserializeBtcTransaction(data, NETWORK_PARAMETERS, true);
BtcTransaction deserializedTxWithoutInputs = BridgeSerializationUtils.deserializeBtcTransaction(data, NETWORK_PARAMETERS, false);

// Assert
assertNull(deserializedTxWithInputs);
assertNull(deserializedTxWithoutInputs);
}

@Test
void serializeAndDeserializeSvpFundTransaction_withValidData_shouldReturnEqualResults() {
// Arrange
BtcTransaction prevTx = new BtcTransaction(NETWORK_PARAMETERS);
prevTx.addOutput(Coin.FIFTY_COINS, ADDRESS);
prevTx.addOutput(Coin.FIFTY_COINS, OTHER_ADDRESS);

BtcTransaction svpFundTx = new BtcTransaction(NETWORK_PARAMETERS);
svpFundTx.addInput(prevTx.getOutput(0));
svpFundTx.addInput(prevTx.getOutput(1));
svpFundTx.addOutput(Coin.COIN, OTHER_ADDRESS);

// Act
byte[] serializedSvpFundTransaction = BridgeSerializationUtils.serializeBtcTransaction(svpFundTx);
BtcTransaction deserializedSvpFundTransaction = BridgeSerializationUtils.deserializeSvpFundTx(serializedSvpFundTransaction, NETWORK_PARAMETERS);

// Assert
assertNotNull(serializedSvpFundTransaction);
assertNotNull(deserializedSvpFundTransaction);
assertEquals(svpFundTx, deserializedSvpFundTransaction);
}

@ParameterizedTest
@NullSource
@EmptySource
void deserializeBtcTransaction_whenInvalidData_shouldReturnNull(byte[] data) {
void deserializeSvpFundTransaction_withInvalidData_shouldReturnNull(byte[] data) {
// Act
BtcTransaction result = BridgeSerializationUtils.deserializeBtcTransaction(data, NETWORK_PARAMETERS);
BtcTransaction result = BridgeSerializationUtils.deserializeSvpFundTx(data, NETWORK_PARAMETERS);

// Assert
assertNull(result);
Expand All @@ -137,7 +192,7 @@ void serializeAndDeserializeRskTxWaitingForSignatures_whenValidData_shouldReturn
byte[] serializedEntry =
BridgeSerializationUtils.serializeRskTxWaitingForSignatures(pegoutTxWaitingForSiganturesEntry);
Map.Entry<Keccak256, BtcTransaction> deserializedEntry =
BridgeSerializationUtils.deserializeRskTxWaitingForSignatures(serializedEntry, NETWORK_PARAMETERS, false);
BridgeSerializationUtils.deserializeRskTxWaitingForSignatures(serializedEntry, NETWORK_PARAMETERS);

// Assert
assertNotNull(serializedEntry);
Expand All @@ -154,7 +209,7 @@ void serializeAndDeserializeRskTxWaitingForSignatures_whenValidData_shouldReturn
void deserializeRskTxWaitingForSignatures_whenInvalidData_shouldReturnEmptyResult(byte[] data) {
// Act
Map.Entry<Keccak256, BtcTransaction> result =
BridgeSerializationUtils.deserializeRskTxWaitingForSignatures(data, NETWORK_PARAMETERS, false);
BridgeSerializationUtils.deserializeRskTxWaitingForSignatures(data, NETWORK_PARAMETERS);

// Assert
assertNotNull(result);
Expand Down Expand Up @@ -186,7 +241,7 @@ void serializeAndDeserializeRskTxsWaitingForSignatures_whenValidEntries_shouldRe
byte[] serializedRskTxsWaitingForSignaturesMap =
BridgeSerializationUtils.serializeRskTxsWaitingForSignatures(rskTxsWaitingForSignaturesMap);
SortedMap<Keccak256, BtcTransaction> deserializedRskTxsWaitingForSignaturesMap =
BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(serializedRskTxsWaitingForSignaturesMap, NETWORK_PARAMETERS, false);
BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(serializedRskTxsWaitingForSignaturesMap, NETWORK_PARAMETERS);

// Assert
assertNotNull(serializedRskTxsWaitingForSignaturesMap);
Expand All @@ -201,7 +256,7 @@ void serializeAndDeserializeRskTxsWaitingForSignatures_whenValidEntries_shouldRe
void deserializeRskTxsWaitingForSignatures_whenInvalidData_shouldReturnEmptyResult(byte[] data) {
// Act
SortedMap<Keccak256, BtcTransaction> result =
BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(data, NETWORK_PARAMETERS, false);
BridgeSerializationUtils.deserializeRskTxsWaitingForSignatures(data, NETWORK_PARAMETERS);

// Assert
assertNotNull(result);
Expand Down

0 comments on commit cc7bea6

Please sign in to comment.