Skip to content

Commit

Permalink
added a test when a tx is already processed do not modify the state
Browse files Browse the repository at this point in the history
  • Loading branch information
julianlen committed Dec 11, 2024
1 parent 0774b8c commit a017be8
Showing 1 changed file with 85 additions and 39 deletions.
124 changes: 85 additions & 39 deletions rskj-core/src/test/java/co/rsk/peg/RegisterBtcTransactionIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest;
import org.ethereum.core.*;
import org.ethereum.crypto.ECKey;
import org.ethereum.vm.PrecompiledContracts;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.math.BigInteger;
Expand All @@ -32,58 +34,108 @@

public class RegisterBtcTransactionIT {

public static final Coin BTC_TRANSFERRED = Coin.COIN;
private final BridgeConstants bridgeConstants = BridgeMainNetConstants.getInstance();
private final NetworkParameters btcParams = bridgeConstants.getBtcParams();
private final BridgeSupportBuilder bridgeSupportBuilder = BridgeSupportBuilder.builder();

@Test
void whenRegisterALegacyBtcTransaction_shouldRegisterTheNewUtxoAndTransferTheRbtcBalance() {
// Arrange
ActivationConfig.ForBlock activationConfig = ActivationConfigsForTest.all().forBlock(0);
Repository repository = BridgeSupportTestUtil.createRepository();
Repository track = repository.startTracking();
Block rskExecutionBlock = getRskExecutionBlock();

BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider();
FeePerKbSupport feePerKbSupport = getFeePerKbSupport();
private ActivationConfig.ForBlock activationConfig;
private Repository track;
private Repository repository;
private Block rskExecutionBlock;
private BtcLockSenderProvider btcLockSenderProvider;
private FeePerKbSupport feePerKbSupport;
private FederationSupport federationSupport;
private BridgeStorageProvider bridgeStorageProvider;
private BtcBlockStoreWithCache.Factory btcBlockStoreFactory;
private BtcBlockStoreWithCache btcBlockStoreWithCache;
private BtcTransaction bitcoinTransaction;
private PartialMerkleTree pmtWithTransactions;
private int btcBlockWithPmtHeight;
private int chainHeight;
private Transaction rskTx;
private ECKey ecKey;
private RskAddress rskReceiver;
private BridgeSupport bridgeSupport;

@BeforeEach
void setUp() {
rskTx = TransactionUtils.createTransaction();
repository = BridgeSupportTestUtil.createRepository();
track = repository.startTracking();

activationConfig = ActivationConfigsForTest.all().forBlock(0);
rskExecutionBlock = getRskExecutionBlock();

btcLockSenderProvider = new BtcLockSenderProvider();
feePerKbSupport = getFeePerKbSupport();

Federation federation = P2shErpFederationBuilder.builder().build();
FederationStorageProvider federationStorageProvider = getFederationStorageProvider(track, federation);
FederationSupport federationSupport = getFederationSupport(federationStorageProvider, activationConfig, bridgeConstants.getFederationConstants());
federationSupport = getFederationSupport(federationStorageProvider, activationConfig, bridgeConstants.getFederationConstants());

bridgeStorageProvider = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants.getBtcParams(), activationConfig);
btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeConstants.getBtcParams(), 100, 100);
btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(track, bridgeConstants, bridgeStorageProvider, activationConfig);

BtcECKey btcPublicKey = new BtcECKey();
Coin btcTransferred = Coin.COIN;
BtcTransaction bitcoinTransaction = createPegInTransaction(federationSupport.getActiveFederation().getAddress(), btcTransferred, btcPublicKey);
ecKey = ECKey.fromPublicOnly(btcPublicKey.getPubKey());
rskReceiver = new RskAddress(ecKey.getAddress());
bitcoinTransaction = createPegInTransaction(federationSupport.getActiveFederation().getAddress(), BTC_TRANSFERRED, btcPublicKey);

pmtWithTransactions = createValidPmtForTransactions(Collections.singletonList(bitcoinTransaction.getHash()), bridgeConstants.getBtcParams());
btcBlockWithPmtHeight = bridgeConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeConstants.getPegoutTxIndexGracePeriodInBtcBlocks();
chainHeight = btcBlockWithPmtHeight + bridgeConstants.getBtc2RskMinimumAcceptableConfirmations();

recreateChainFromPmtOrFail();
bridgeStorageProvider.save();
bridgeSupport = getBridgeSupport(bridgeStorageProvider, activationConfig, federationSupport, feePerKbSupport, rskExecutionBlock, btcBlockStoreFactory, track, btcLockSenderProvider);
}

@Test
void whenRegisterALegacyBtcTransaction_shouldRegisterTheNewUtxoAndTransferTheRbtcBalance() {
// Arrange
TransactionOutput output = bitcoinTransaction.getOutput(0);
UTXO utxo = getUtxo(bitcoinTransaction, output);
List<UTXO> expectedFederationUtxos = Collections.singletonList(utxo);

BridgeStorageProvider bridgeStorageProvider = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants.getBtcParams(), activationConfig);
BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeConstants.getBtcParams(), 100, 100);
BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(track, bridgeConstants, bridgeStorageProvider, activationConfig);
co.rsk.core.Coin receiverBalance = track.getBalance(rskReceiver);
co.rsk.core.Coin expectedReceiverBalance = receiverBalance.add(co.rsk.core.Coin.fromBitcoin(BTC_TRANSFERRED));

PartialMerkleTree pmtWithTransactions = createValidPmtForTransactions(Collections.singletonList(bitcoinTransaction.getHash()), bridgeConstants.getBtcParams());
int btcBlockWithPmtHeight = bridgeConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeConstants.getPegoutTxIndexGracePeriodInBtcBlocks();
int chainHeight = btcBlockWithPmtHeight + bridgeConstants.getBtc2RskMinimumAcceptableConfirmations();
// Act
registerBtcTransactionOrFail();

// Assert
try {
recreateChainFromPmt(btcBlockStoreWithCache, chainHeight, pmtWithTransactions, btcBlockWithPmtHeight, bridgeConstants.getBtcParams());
} catch (BlockStoreException e) {
Optional<Long> heightIfBtcTxHashIsAlreadyProcessed = bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(bitcoinTransaction.getHash());
assertTrue(heightIfBtcTxHashIsAlreadyProcessed.isPresent());
assertEquals(rskExecutionBlock.getNumber(), heightIfBtcTxHashIsAlreadyProcessed.get());
} catch (IOException e) {
fail(e.getMessage());
}

bridgeStorageProvider.save();
assertEquals(expectedFederationUtxos, federationSupport.getActiveFederationBtcUTXOs());
assertEquals(expectedReceiverBalance, repository.getBalance(rskReceiver));

BridgeSupport bridgeSupport = getBridgeSupport(bridgeStorageProvider, activationConfig, federationSupport, feePerKbSupport, rskExecutionBlock, btcBlockStoreFactory, track, btcLockSenderProvider);
}

Transaction rskTx = TransactionUtils.createTransaction();
org.ethereum.crypto.ECKey key = org.ethereum.crypto.ECKey.fromPublicOnly(btcPublicKey.getPubKey());
@Test
void whenRegisterARepeatedLegacyBtcTransaction_shouldNotPerformAnyChange() {
// Arrange
registerBtcTransactionOrFail();

RskAddress receiver = new RskAddress(key.getAddress());
co.rsk.core.Coin receiverBalance = track.getBalance(receiver);
co.rsk.core.Coin expectedReceiverBalance = receiverBalance.add(co.rsk.core.Coin.fromBitcoin(btcTransferred));
RskAddress receiverBalance = new RskAddress(ecKey.getAddress());
co.rsk.core.Coin expectedReceiverBalance = track.getBalance(receiverBalance);
List<UTXO> expectedFederationUTXOs = federationSupport.getActiveFederationBtcUTXOs();

// Act
registerBtcTransactionOrFail();

// Assert
assertEquals(expectedFederationUTXOs, federationSupport.getActiveFederationBtcUTXOs());
assertEquals(expectedReceiverBalance, repository.getBalance(receiverBalance));
}

private void registerBtcTransactionOrFail() {
try {
bridgeSupport.registerBtcTransaction(rskTx, bitcoinTransaction.bitcoinSerialize(), btcBlockWithPmtHeight, pmtWithTransactions.bitcoinSerialize());
} catch (Exception e) {
Expand All @@ -92,20 +144,14 @@ void whenRegisterALegacyBtcTransaction_shouldRegisterTheNewUtxoAndTransferTheRbt

bridgeSupport.save();
track.commit();
}

// Assert

private void recreateChainFromPmtOrFail() {
try {
Optional<Long> heightIfBtcTxHashIsAlreadyProcessed = bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(bitcoinTransaction.getHash());
assertTrue(heightIfBtcTxHashIsAlreadyProcessed.isPresent());
assertEquals(rskExecutionBlock.getNumber(), heightIfBtcTxHashIsAlreadyProcessed.get());
} catch (IOException e) {
recreateChainFromPmt(btcBlockStoreWithCache, chainHeight, pmtWithTransactions, btcBlockWithPmtHeight, bridgeConstants.getBtcParams());
} catch (BlockStoreException e) {
fail(e.getMessage());
}

assertEquals(expectedFederationUtxos, federationSupport.getActiveFederationBtcUTXOs());
assertEquals(expectedReceiverBalance, repository.getBalance(receiver));

}

private static UTXO getUtxo(BtcTransaction bitcoinTransaction, TransactionOutput output) {
Expand Down

0 comments on commit a017be8

Please sign in to comment.