Skip to content

Commit

Permalink
Legacy peg in happy path (#2886)
Browse files Browse the repository at this point in the history
* feat: first happy path for a peg in

* fix: declaration of utxo

* fix: black space at the end of the file

* fix: assert that the event pegin_btc has been emitted with the correct parameters

* feat: replaced mocked feePerKeb constant for an actual instance

* fix: now the peg in uses the minimum pegin tx value

* fix: moved the method getRskExecutionBlock to BridgeSupoprtTestUtil

* fix: using BitcoinTestUtils to make the btcPublicKey generation deterministic

* fix: erased extra line

* fix: added in BridgeSupportIT an extra line in the end

* fix: removed the public modifier in the RegisterBTCTransactionIT

* fix: renamed getUtxo to utxoOf
  • Loading branch information
julianlen committed Dec 16, 2024
1 parent 5c9e371 commit e0c0cc6
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 15 deletions.
17 changes: 3 additions & 14 deletions rskj-core/src/test/java/co/rsk/peg/BridgeSupportIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
package co.rsk.peg;

import static co.rsk.peg.BridgeSupportTestUtil.createFederationStorageProvider;
import static co.rsk.peg.BridgeSupportTestUtil.createRepository;
import static co.rsk.peg.PegTestUtils.createFederation;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
Expand All @@ -36,8 +38,6 @@
import co.rsk.core.BlockDifficulty;
import co.rsk.core.RskAddress;
import co.rsk.crypto.Keccak256;
import co.rsk.db.MutableTrieCache;
import co.rsk.db.MutableTrieImpl;
import co.rsk.peg.bitcoin.BitcoinTestUtils;
import co.rsk.peg.bitcoin.MerkleBranch;
import co.rsk.peg.btcLockSender.BtcLockSenderProvider;
Expand All @@ -56,7 +56,6 @@
import co.rsk.peg.whitelist.*;
import co.rsk.peg.whitelist.constants.WhitelistMainNetConstants;
import co.rsk.test.builders.*;
import co.rsk.trie.Trie;
import com.google.common.collect.Lists;
import java.io.*;
import java.math.BigInteger;
Expand All @@ -80,7 +79,6 @@
import org.ethereum.core.*;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.MutableRepository;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.PrecompiledContracts;
import org.ethereum.vm.program.InternalTransaction;
Expand Down Expand Up @@ -4366,13 +4364,4 @@ private void mockChainOfStoredBlocks(BtcBlockStoreWithCache btcBlockStore, BtcBl
when(btcBlockStore.getChainHead()).thenReturn(currentStored);
when(currentStored.getHeight()).thenReturn(headHeight);
}

public static Repository createRepository() {
return new MutableRepository(new MutableTrieCache(new MutableTrieImpl(null, new Trie())));
}

private FederationStorageProvider createFederationStorageProvider(Repository repository) {
StorageAccessor bridgeStorageAccessor = new BridgeStorageAccessorImpl(repository);
return new FederationStorageProviderImpl(bridgeStorageAccessor);
}
}
}
25 changes: 24 additions & 1 deletion rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@
import co.rsk.db.MutableTrieCache;
import co.rsk.db.MutableTrieImpl;
import co.rsk.peg.bitcoin.BitcoinTestUtils;
import co.rsk.peg.federation.FederationStorageProvider;
import co.rsk.peg.federation.FederationStorageProviderImpl;
import co.rsk.peg.storage.BridgeStorageAccessorImpl;
import co.rsk.peg.storage.StorageAccessor;
import co.rsk.trie.Trie;
import java.math.BigInteger;
import java.util.*;
import org.bouncycastle.util.encoders.Hex;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.core.Block;
import org.ethereum.core.BlockHeader;
import org.ethereum.core.BlockHeaderBuilder;
import org.ethereum.core.Repository;
import org.ethereum.db.MutableRepository;

Expand Down Expand Up @@ -52,7 +60,7 @@ public static void recreateChainFromPmt(
btcBlockStoreWithCache.setChainHead(storedChainHeadBlock);
}

private static BtcBlock createBtcBlockWithPmt(PartialMerkleTree pmt, NetworkParameters networkParameters) {
public static BtcBlock createBtcBlockWithPmt(PartialMerkleTree pmt, NetworkParameters networkParameters) {
Sha256Hash prevBlockHash = BitcoinTestUtils.createHash(1);
Sha256Hash merkleRoot = pmt.getTxnHashAndMerkleRoot(new ArrayList<>());

Expand Down Expand Up @@ -81,4 +89,19 @@ public static void mockChainOfStoredBlocks(BtcBlockStoreWithCache btcBlockStore,
when(btcBlockStore.getChainHead()).thenReturn(currentStored);
when(currentStored.getHeight()).thenReturn(headHeight);
}

public static FederationStorageProvider createFederationStorageProvider(Repository repository) {
StorageAccessor bridgeStorageAccessor = new BridgeStorageAccessorImpl(repository);
return new FederationStorageProviderImpl(bridgeStorageAccessor);
}

public static Block getRskExecutionBlock() {
long rskExecutionBlockNumber = 1000L;
long rskExecutionBlockTimestamp = 10L;
BlockHeader blockHeader = new BlockHeaderBuilder(mock(ActivationConfig.class))
.setNumber(rskExecutionBlockNumber)
.setTimestamp(rskExecutionBlockTimestamp)
.build();
return Block.createBlockFromHeader(blockHeader, true);
}
}
156 changes: 156 additions & 0 deletions rskj-core/src/test/java/co/rsk/peg/RegisterBtcTransactionIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package co.rsk.peg;

import static co.rsk.peg.BridgeSupportTestUtil.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import co.rsk.bitcoinj.core.*;
import co.rsk.bitcoinj.script.ScriptBuilder;
import co.rsk.core.RskAddress;
import co.rsk.net.utils.TransactionUtils;
import co.rsk.peg.bitcoin.BitcoinTestUtils;
import co.rsk.peg.btcLockSender.BtcLockSenderProvider;
import co.rsk.peg.constants.BridgeConstants;
import co.rsk.peg.constants.BridgeMainNetConstants;
import co.rsk.peg.federation.*;
import co.rsk.peg.federation.constants.FederationConstants;
import co.rsk.peg.feeperkb.FeePerKbStorageProvider;
import co.rsk.peg.feeperkb.FeePerKbStorageProviderImpl;
import co.rsk.peg.feeperkb.FeePerKbSupport;
import co.rsk.peg.feeperkb.FeePerKbSupportImpl;
import co.rsk.peg.storage.BridgeStorageAccessorImpl;
import co.rsk.peg.storage.StorageAccessor;
import co.rsk.peg.utils.BridgeEventLoggerImpl;
import co.rsk.test.builders.BridgeSupportBuilder;
import co.rsk.test.builders.FederationSupportBuilder;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest;
import org.ethereum.core.*;
import org.ethereum.vm.PrecompiledContracts;
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();

@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();

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));

BridgeStorageProvider 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();
int chainHeight = btcBlockWithPmtHeight + bridgeConstants.getBtc2RskMinimumAcceptableConfirmations();

BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activations, new ArrayList<>()));

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

bridgeStorageProvider.save();

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());

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));

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

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

// 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));

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

private static UTXO utxoOf(BtcTransaction bitcoinTransaction, TransactionOutput output) {
return new UTXO(
bitcoinTransaction.getHash(),
output.getIndex(),
output.getValue(),
0,
bitcoinTransaction.isCoinBase(),
output.getScriptPubKey()
);
}

private static FederationSupport getFederationSupport(FederationStorageProvider federationStorageProvider, ActivationConfig.ForBlock activationConfig, FederationConstants federationConstants) {
return FederationSupportBuilder.builder()
.withFederationConstants(federationConstants)
.withFederationStorageProvider(federationStorageProvider)
.withActivations(activationConfig)
.build();
}

private FederationStorageProvider getFederationStorageProvider(Repository track, Federation federation) {
FederationStorageProvider federationStorageProvider = createFederationStorageProvider(track);
federationStorageProvider.setNewFederation(federation);
return federationStorageProvider;
}

private static FeePerKbSupport getFeePerKbSupport(Repository repository, BridgeConstants bridgeConstants) {
StorageAccessor bridgeStorageAccessor = new BridgeStorageAccessorImpl(repository);
FeePerKbStorageProvider feePerKbStorageProvider = new FeePerKbStorageProviderImpl(bridgeStorageAccessor);
return new FeePerKbSupportImpl(
bridgeConstants.getFeePerKbConstants(),
feePerKbStorageProvider
);
}

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));
btcTx.addOutput(new TransactionOutput(btcParams, btcTx, coin, federationAddress));

return btcTx;
}
}

0 comments on commit e0c0cc6

Please sign in to comment.