From 59e12028c8a4a491ae0a7204d3006526db74b27e Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Mon, 13 May 2024 01:50:27 -0400 Subject: [PATCH] - Change updateBridgeBtcTransactions in order to skip bech32 transactions - Add tests --- .../java/co/rsk/federate/BtcToRskClient.java | 21 ++-- .../co/rsk/federate/BtcToRskClientTest.java | 95 +++++++++++++++++-- 2 files changed, 102 insertions(+), 14 deletions(-) diff --git a/src/main/java/co/rsk/federate/BtcToRskClient.java b/src/main/java/co/rsk/federate/BtcToRskClient.java index 0653da63a..4630d861d 100644 --- a/src/main/java/co/rsk/federate/BtcToRskClient.java +++ b/src/main/java/co/rsk/federate/BtcToRskClient.java @@ -571,14 +571,15 @@ protected void updateBridgeBtcTransactions() { btcTx.getHash() ); logger.warn("[updateBridgeBtcTransactions] {}", message); - // If tx sender could be retrieved then let the Bridge process the tx and refund the sender - if (peginInformation.getSenderBtcAddress() != null) { - logger.warn("[updateBridgeBtcTransactions] Funds will be refunded to sender."); - } else { - // Remove the tx from the set to be sent to the Bridge since it's not processable - txsToSendToRskHashes.remove(txHash); - continue; - } + } + + // If tx sender could be retrieved then let the Bridge process the tx and refund the sender + if (canSenderBeRetrieved(peginInformation)) { + logger.warn("[updateBridgeBtcTransactions] Funds will be refunded to sender."); + } else { + // Remove the tx from the set to be sent to the Bridge since it's not processable + txsToSendToRskHashes.remove(txHash); + continue; } // Check if the tx can be processed by the Bridge @@ -668,6 +669,10 @@ protected void updateBridgeBtcTransactions() { } } + private static boolean canSenderBeRetrieved(PeginInformation peginInformation) { + return !(peginInformation.getSenderBtcAddress() == null && peginInformation.getSenderBtcAddressType() == TxSenderAddressType.UNKNOWN); + } + /** * Gets the first ready to be informed coinbase transaction and informs it */ diff --git a/src/test/java/co/rsk/federate/BtcToRskClientTest.java b/src/test/java/co/rsk/federate/BtcToRskClientTest.java index 1821a3553..67e6e8594 100644 --- a/src/test/java/co/rsk/federate/BtcToRskClientTest.java +++ b/src/test/java/co/rsk/federate/BtcToRskClientTest.java @@ -1,5 +1,6 @@ package co.rsk.federate; +import static org.bitcoinj.core.Coin.COIN; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -38,7 +39,6 @@ import co.rsk.federate.mock.SimpleBtcTransaction; import co.rsk.federate.mock.SimpleFederatorSupport; import co.rsk.net.NodeBlockProcessor; -import co.rsk.peg.BridgeUtils; import co.rsk.peg.PegUtilsLegacy; import co.rsk.peg.federation.Federation; import co.rsk.peg.federation.FederationMember; @@ -1932,7 +1932,7 @@ void updateTransactionWithSenderUnknown_after_rskip170() throws Exception { federatorSupport.getTxsSentToRegisterBtcTransaction(); assertNotNull(txsSentToRegisterBtcTransaction); - assertFalse(txsSentToRegisterBtcTransaction.isEmpty()); + assertTrue(txsSentToRegisterBtcTransaction.isEmpty()); } @Test @@ -2486,6 +2486,78 @@ void updateBridgeBtcTransactions_tx_with_witness_already_informed() throws Excep verify(federatorSupport, never()).sendRegisterBtcTransaction(any(Transaction.class), anyInt(), any(PartialMerkleTree.class)); } + @Test + void updateBridgeBtcTransactions_bech32_sender_should_not_be_sent() throws Exception { + ActivationConfig activationConfig = mock(ActivationConfig.class); + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + when(activations.isActive(ConsensusRule.RSKIP170)).thenReturn(true); + when(activations.isActive(ConsensusRule.RSKIP379)).thenReturn(true); + when(activationConfig.forBlock(anyLong())).thenReturn(activations); + + NodeBlockProcessor nodeBlockProcessor = mock(NodeBlockProcessor.class); + when(nodeBlockProcessor.hasBetterBlockToSync()).thenReturn(false); + + SimpleBtcTransaction fundingTx = new SimpleBtcTransaction(networkParameters, createHash(), createHash(), false); + + int outputIndex = 0; + fundingTx.addInput(createHash(), outputIndex, new Script(new byte[]{})); + fundingTx.addOutput(createBech32Output(networkParameters, COIN)); + + SimpleBtcTransaction bech32PeginTx = new SimpleBtcTransaction(networkParameters, createHash(), createHash(), false); + bech32PeginTx.addInput(fundingTx.getOutput(outputIndex)); + bech32PeginTx.addOutput(COIN.div(2), Address.fromString(networkParameters, genesisFederation.getAddress().toBase58())); + + FederatorSupport federatorSupport = mock(FederatorSupport.class); + when(federatorSupport.getBtcBestBlockChainHeight()).thenReturn(1); + when(federatorSupport.isBtcTxHashAlreadyProcessed(bech32PeginTx.getTxId())).thenReturn(false); + when(federatorSupport.getBtcTxHashProcessedHeight(bech32PeginTx.getTxId())).thenReturn(-1L); + when(federatorSupport.getFederationMember()).thenReturn(fakeMember); + + BtcToRskClient btcToRskClient = new BtcToRskClient.Factory(federatorSupport, nodeBlockProcessor).build(); + + BitcoinWrapper bitcoinWrapper = mock(BitcoinWrapper.class); + + Map txsInWallet = new HashMap<>(); + txsInWallet.put(bech32PeginTx.getWTxId(), bech32PeginTx); + when( + bitcoinWrapper.getTransactionMap( + bridgeRegTestConstants.getBtc2RskMinimumAcceptableConfirmations() + ) + ).thenReturn(txsInWallet); + + BtcToRskClientFileStorage btcToRskClientFileStorageMock = mock(BtcToRskClientFileStorage.class); + BtcToRskClientFileData btcToRskClientFileData = mock(BtcToRskClientFileData.class); + when(btcToRskClientFileStorageMock.read(any())).thenReturn(new BtcToRskClientFileReadResult(true, btcToRskClientFileData)); + + HashMap> transactionProofs = new HashMap<>(); + when(btcToRskClientFileData.getTransactionProofs()).thenReturn(transactionProofs); + + List proofs = new ArrayList<>(); + Proof proof = mock(Proof.class); + proofs.add(proof); + btcToRskClientFileData.getTransactionProofs().put(bech32PeginTx.getWTxId(), proofs); + + BtcLockSenderProvider btcLockSender = new BtcLockSenderProvider(); + PeginInstructionsProvider peginInstructionsProvider = new PeginInstructionsProvider(); + + btcToRskClient.setup( + activationConfig, + bitcoinWrapper, + bridgeRegTestConstants, + btcToRskClientFileStorageMock, + btcLockSender, + peginInstructionsProvider, + false, + 100 + ); + btcToRskClient.start(genesisFederation); + btcToRskClient.updateBridgeBtcTransactions(); + + assertTrue(transactionProofs.isEmpty()); + verify(federatorSupport, never()).isBtcTxHashAlreadyProcessed(bech32PeginTx.getTxId()); + verify(federatorSupport, never()).sendRegisterBtcTransaction(any(Transaction.class), anyInt(), any(PartialMerkleTree.class)); + } + private static co.rsk.bitcoinj.script.Script createBaseInputScriptThatSpendsFromTheFederation(Federation federation) { co.rsk.bitcoinj.script.Script scriptPubKey = federation.getP2SHScript(); @@ -2558,7 +2630,7 @@ private Block createBlock(Sha256Hash blockHash, Transaction... txs) { private Transaction createTransaction() { Transaction tx = new SimpleBtcTransaction(networkParameters, createHash(), createHash(), false); tx.addInput(Sha256Hash.ZERO_HASH, 0, org.bitcoinj.script.ScriptBuilder.createInputScript(null, new ECKey())); - tx.addOutput(Coin.COIN, Address.fromString(networkParameters, genesisFederation.getAddress().toBase58())); + tx.addOutput(COIN, Address.fromString(networkParameters, genesisFederation.getAddress().toBase58())); return tx; } @@ -2566,11 +2638,22 @@ private Transaction createTransaction() { private Transaction createSegwitTransaction() { Transaction tx = new SimpleBtcTransaction(networkParameters, createHash(), createHash(), true); tx.addInput(Sha256Hash.ZERO_HASH, 0, org.bitcoinj.script.ScriptBuilder.createInputScript(null, new ECKey())); - tx.addOutput(Coin.COIN, Address.fromString(networkParameters, genesisFederation.getAddress().toBase58())); + tx.addOutput(COIN, Address.fromString(networkParameters, genesisFederation.getAddress().toBase58())); return tx; } + private TransactionOutput createBech32Output(NetworkParameters networkParameters, Coin valuesToSend) { + byte[] scriptBytes = networkParameters.getId().equals( + NetworkParameters.ID_MAINNET)? + Hex.decode("001437c383ea78269585c73289daa36d7b7014b65294") : + Hex.decode("0014ef57424d0d625cf82fabe4fd7657d24a5f13dfb2"); + return new TransactionOutput(networkParameters, null, + valuesToSend, + scriptBytes + ); + } + private Sha256Hash createHash() { byte[] bytes = new byte[32]; bytes[0] = (byte) ++nhash; @@ -2656,7 +2739,7 @@ private Transaction getCoinbaseTx(boolean hasWitness, Sha256Hash witnessRoot, by } input.setScriptSig(new Script(new byte[]{0,0})); tx.addInput(input); - TransactionOutput output = new TransactionOutput(networkParameters, null, Coin.COIN, Address.fromString(networkParameters, "mvbnrCX3bg1cDRUu8pkecrvP6vQkSLDSou")); + TransactionOutput output = new TransactionOutput(networkParameters, null, COIN, Address.fromString(networkParameters, "mvbnrCX3bg1cDRUu8pkecrvP6vQkSLDSou")); tx.addOutput(output); byte[] witnessCommitment = Sha256Hash.twiceOf(witnessRoot.getReversedBytes(), witnessReservedValue).getBytes(); @@ -2683,7 +2766,7 @@ private Transaction getTx(boolean hasWitness) { input.setWitness(witness); } tx.addInput(input); - TransactionOutput output = new TransactionOutput(networkParameters, null, Coin.COIN, Address.fromString(networkParameters, "mvbnrCX3bg1cDRUu8pkecrvP6vQkSLDSou")); + TransactionOutput output = new TransactionOutput(networkParameters, null, COIN, Address.fromString(networkParameters, "mvbnrCX3bg1cDRUu8pkecrvP6vQkSLDSou")); tx.addOutput(output); return tx;