Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Register twice the same transaction, the second time should not modify any state #2893

Open
wants to merge 14 commits into
base: pegin-tests-integration
Choose a base branch
from
Open
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 85 additions & 53 deletions rskj-core/src/test/java/co/rsk/peg/RegisterBtcTransactionIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,75 +26,125 @@
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.util.*;

class RegisterBtcTransactionIT {

private final BridgeConstants bridgeConstants = BridgeMainNetConstants.getInstance();
private final NetworkParameters btcParams = bridgeConstants.getBtcParams();
private final BridgeSupportBuilder bridgeSupportBuilder = BridgeSupportBuilder.builder();
private Repository track;
private Repository repository;
private Block rskExecutionBlock;
private FederationSupport federationSupport;
private BridgeStorageProvider bridgeStorageProvider;
private BtcTransaction bitcoinTransaction;
private PartialMerkleTree pmtWithTransactions;
private int btcBlockWithPmtHeight;
private Transaction rskTx;
private RskAddress rskReceiver;
private BridgeSupport bridgeSupport;
private BridgeEventLoggerImpl bridgeEventLogger;
private Coin btcTransferred;

@BeforeEach
void setUp() throws Exception{
julia-zack marked this conversation as resolved.
Show resolved Hide resolved
rskTx = TransactionUtils.createTransaction();
repository = BridgeSupportTestUtil.createRepository();
track = repository.startTracking();

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

BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider();
FeePerKbSupport feePerKbSupport = getFeePerKbSupport(repository, bridgeConstants);

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

BtcECKey btcPublicKey = BitcoinTestUtils.getBtcEcKeyFromSeed("seed");
Coin btcTransferred = bridgeConstants.getMinimumPeginTxValue(activations);
BtcTransaction bitcoinTransaction = createPegInTransaction(federationSupport.getActiveFederation().getAddress(), btcTransferred, btcPublicKey);
TransactionOutput output = bitcoinTransaction.getOutput(0);
List<UTXO> expectedFederationUtxos = Collections.singletonList(utxoOf(bitcoinTransaction, output));
FederationConstants federationConstants = bridgeConstants.getFederationConstants();
federationSupport = FederationSupportBuilder.builder()
.withFederationConstants(federationConstants)
.withFederationStorageProvider(federationStorageProvider)
.withActivations(activations)
.build();

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

PartialMerkleTree pmtWithTransactions = createValidPmtForTransactions(Collections.singletonList(bitcoinTransaction.getHash()), bridgeConstants.getBtcParams());
int btcBlockWithPmtHeight = bridgeConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeConstants.getPegoutTxIndexGracePeriodInBtcBlocks();
BtcECKey btcPublicKey = BitcoinTestUtils.getBtcEcKeyFromSeed("seed");
rskReceiver = getRskReceiver(btcPublicKey);
julia-zack marked this conversation as resolved.
Show resolved Hide resolved
btcTransferred = bridgeConstants.getMinimumPeginTxValue(activations);
bitcoinTransaction = createPegInTransaction(federationSupport.getActiveFederation().getAddress(), btcTransferred, btcPublicKey);

pmtWithTransactions = createValidPmtForTransactions(List.of(bitcoinTransaction.getHash()), bridgeConstants.getBtcParams());
btcBlockWithPmtHeight = bridgeConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeConstants.getPegoutTxIndexGracePeriodInBtcBlocks();
int chainHeight = btcBlockWithPmtHeight + bridgeConstants.getBtc2RskMinimumAcceptableConfirmations();

BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activations, new ArrayList<>()));
bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activations, new ArrayList<>()));
julia-zack marked this conversation as resolved.
Show resolved Hide resolved

recreateChainFromPmt(btcBlockStoreWithCache, chainHeight, pmtWithTransactions, btcBlockWithPmtHeight, bridgeConstants.getBtcParams());

bridgeStorageProvider.save();
bridgeSupport = bridgeSupportBuilder
.withBridgeConstants(bridgeConstants)
.withProvider(bridgeStorageProvider)
.withActivations(activations)
.withEventLogger(bridgeEventLogger)
.withFederationSupport(federationSupport)
.withFeePerKbSupport(feePerKbSupport)
.withExecutionBlock(rskExecutionBlock)
.withBtcBlockStoreFactory(btcBlockStoreFactory)
.withRepository(track)
.withBtcLockSenderProvider(btcLockSenderProvider)
.build();
}

BridgeSupport bridgeSupport = getBridgeSupport(bridgeEventLogger, bridgeStorageProvider, activations, federationSupport, feePerKbSupport, rskExecutionBlock, btcBlockStoreFactory, track, btcLockSenderProvider);

Transaction rskTx = TransactionUtils.createTransaction();
org.ethereum.crypto.ECKey key = org.ethereum.crypto.ECKey.fromPublicOnly(btcPublicKey.getPubKey());
@Test
void whenRegisterALegacyBtcTransaction_shouldRegisterTheNewUtxoAndTransferTheRbtcBalance() throws Exception {
julia-zack marked this conversation as resolved.
Show resolved Hide resolved
// Arrange
TransactionOutput output = bitcoinTransaction.getOutput(0);
List<UTXO> expectedFederationUtxos = Collections.singletonList(utxoOf(bitcoinTransaction, output));

RskAddress receiver = new RskAddress(key.getAddress());
co.rsk.core.Coin receiverBalance = track.getBalance(receiver);
co.rsk.core.Coin receiverBalance = track.getBalance(rskReceiver);
co.rsk.core.Coin expectedReceiverBalance = receiverBalance.add(co.rsk.core.Coin.fromBitcoin(btcTransferred));

// Act
bridgeSupport.registerBtcTransaction(rskTx, bitcoinTransaction.bitcoinSerialize(), btcBlockWithPmtHeight, pmtWithTransactions.bitcoinSerialize());

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

// Assert
Optional<Long> heightIfBtcTxHashIsAlreadyProcessed = bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(bitcoinTransaction.getHash());

assertTrue(heightIfBtcTxHashIsAlreadyProcessed.isPresent());
assertEquals(rskExecutionBlock.getNumber(), heightIfBtcTxHashIsAlreadyProcessed.get());
assertEquals(expectedFederationUtxos, federationSupport.getActiveFederationBtcUTXOs());
assertEquals(expectedReceiverBalance, repository.getBalance(receiver));
assertEquals(expectedReceiverBalance, repository.getBalance(rskReceiver));

verify(bridgeEventLogger, times(1)).logPeginBtc(rskReceiver, bitcoinTransaction, btcTransferred, 0);

}

@Test
void whenRegisterARepeatedLegacyBtcTransaction_shouldNotPerformAnyChange() throws Exception {
// Arrange
registerBtcTransactionAndCommit();

co.rsk.core.Coin expectedReceiverBalance = track.getBalance(rskReceiver);
List<UTXO> expectedFederationUTXOs = federationSupport.getActiveFederationBtcUTXOs();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i just noticed that here you are pointing the reference to the utxos, so you end up asserting
federationSupport.getActiveFederationBtcUTXOs().equals(federationSupport.getActiveFederationBtcUTXOs())


// Act
registerBtcTransactionAndCommit();

verify(bridgeEventLogger, times(1)).logPeginBtc(receiver, bitcoinTransaction, btcTransferred, 0);
// Assert
assertEquals(expectedFederationUTXOs, federationSupport.getActiveFederationBtcUTXOs());
assertEquals(expectedReceiverBalance, repository.getBalance(rskReceiver));
}

private void registerBtcTransactionAndCommit() throws Exception {
bridgeSupport.registerBtcTransaction(rskTx, bitcoinTransaction.bitcoinSerialize(), btcBlockWithPmtHeight, pmtWithTransactions.bitcoinSerialize());
bridgeSupport.save();
track.commit();
}

private static UTXO utxoOf(BtcTransaction bitcoinTransaction, TransactionOutput output) {
Expand All @@ -108,12 +158,9 @@ private static UTXO utxoOf(BtcTransaction bitcoinTransaction, TransactionOutput
);
}

private static FederationSupport getFederationSupport(FederationStorageProvider federationStorageProvider, ActivationConfig.ForBlock activationConfig, FederationConstants federationConstants) {
return FederationSupportBuilder.builder()
.withFederationConstants(federationConstants)
.withFederationStorageProvider(federationStorageProvider)
.withActivations(activationConfig)
.build();
private RskAddress getRskReceiver(BtcECKey btcPublicKey) {
ECKey ecKey = ECKey.fromPublicOnly(btcPublicKey.getPubKey());
return new RskAddress(ecKey.getAddress());
}

private FederationStorageProvider getFederationStorageProvider(Repository track, Federation federation) {
Expand All @@ -131,21 +178,6 @@ private static FeePerKbSupport getFeePerKbSupport(Repository repository, BridgeC
);
}

private BridgeSupport getBridgeSupport(BridgeEventLoggerImpl bridgeEventLogger, BridgeStorageProvider bridgeStorageProvider, ActivationConfig.ForBlock activationsBeforeForks, FederationSupport federationSupport, FeePerKbSupport feePerKbSupport, Block rskExecutionBlock, BtcBlockStoreWithCache.Factory btcBlockStoreFactory, Repository repository, BtcLockSenderProvider btcLockSenderProvider) {
return bridgeSupportBuilder
.withBridgeConstants(bridgeConstants)
.withProvider(bridgeStorageProvider)
.withEventLogger(bridgeEventLogger)
.withActivations(activationsBeforeForks)
.withFederationSupport(federationSupport)
.withFeePerKbSupport(feePerKbSupport)
.withExecutionBlock(rskExecutionBlock)
.withBtcBlockStoreFactory(btcBlockStoreFactory)
.withRepository(repository)
.withBtcLockSenderProvider(btcLockSenderProvider)
.build();
}

private BtcTransaction createPegInTransaction(Address federationAddress, Coin coin, BtcECKey pubKey) {
BtcTransaction btcTx = new BtcTransaction(btcParams);
btcTx.addInput(BitcoinTestUtils.createHash(0), 0, ScriptBuilder.createInputScript(null, pubKey));
Expand Down
Loading