Skip to content

Commit

Permalink
Avoiding deep nested functions in tests by calling utility functions.…
Browse files Browse the repository at this point in the history
… Refactors.
  • Loading branch information
jeremy-then committed Sep 18, 2024
1 parent 546d9a1 commit d280986
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 45 deletions.
2 changes: 1 addition & 1 deletion lib/2wp-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ const createExpectedPeginBtcEvent = (partialExpectedEvent, rskRecipientRskAddres
const expectedEvent = {
...partialExpectedEvent,
arguments: {
receiver: ensure0x(rskRecipientRskAddress),
receiver: rskRecipientRskAddress,
btcTxHash: ensure0x(btcPeginTxHash),
amount: `${peginValueInSatoshis}`,
protocolVersion,
Expand Down
15 changes: 0 additions & 15 deletions lib/assertions/2wp.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,26 +137,11 @@ const assertRejectedPeginEvent = (rejectedPeginTx, expectedRejectionReason, expe
expect(outpointValues.every(value => value in federationUtxoValues)).to.be.true;
}

/**
* Searches for and checks that the pegin_btc event is found in the block.
* @param {RskTransactionHelper} rskTxHelper to make transactions to the rsk network.
* @param {number} atBlock the block number to look for the event.
* @param {BridgeEvent} expectedEvent the expected event to be found in the block.
* @returns {Promise<void>}
*/
const findAndCheckPeginBtcEventInBlock = async (rskTxHelper, atBlock, expectedEvent) => {
const peginBtcEvent = await rskUtils.findEventInBlock(rskTxHelper, expectedEvent.name, atBlock);
expect(peginBtcEvent).to.exist;
peginBtcEvent.arguments.receiver = peginBtcEvent.arguments.receiver.toLowerCase();
expect(peginBtcEvent).to.be.deep.equal(expectedEvent);
};

module.exports = {
with: (btcClient, rskClient, pegClient) => ({
assertBitcoinBalance: assertBitcoinBalance(btcClient, rskClient, pegClient),
assertLock: assertLock(btcClient, rskClient, pegClient),
}),
assertCallToPegoutBatchingBridgeMethods,
assertRejectedPeginEvent,
findAndCheckPeginBtcEventInBlock,
};
92 changes: 63 additions & 29 deletions lib/tests/2wp.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ const { getBridge } = require('../precompiled-abi-forks-util');
const { getBtcClient } = require('../btc-client-provider');
const { getRskTransactionHelpers, getRskTransactionHelper } = require('../rsk-tx-helper-provider');
const { btcToWeis, btcToSatoshis } = require('@rsksmart/btc-eth-unit-converter');
const { waitAndUpdateBridge, mineAndSync } = require('../rsk-utils');
const { waitAndUpdateBridge, mineAndSync, findEventInBlock } = require('../rsk-utils');
const { PEGIN_EVENTS } = require("../constants");
const { findAndCheckPeginBtcEventInBlock } = require('../assertions/2wp');
const { waitForBitcoinTxToBeInMempool } = require('../btc-utils');
const {
ensurePeginIsRegistered,
donateToBridge,
createSenderRecipientInfo,
createExpectedPeginBtcEvent,
mineForPeginRegistration
mineForPeginRegistration,
} = require('../2wp-utils');
const { ensure0x } = require('../utils');
const bitcoinJsLib = require('bitcoinjs-lib');

const DONATION_AMOUNT = 250;
Expand All @@ -32,8 +32,8 @@ const setupBridgeDonation = async (rskTxHelpers, btcTxHelper) => {
await donateToBridge(rskTxHelpers[0], btcTxHelper, donatingBtcAddressInformation, DONATION_AMOUNT);
};

const addInputs = (tx, utxos) => {
utxos.forEach(uxto => {
const addInputs = (tx, sendersUtxosInfo) => {
sendersUtxosInfo.flatMap(senderUtxosInfo => senderUtxosInfo.utxos).forEach(uxto => {
tx.addInput(Buffer.from(uxto.txid, 'hex').reverse(), uxto.vout);
});
};
Expand All @@ -58,12 +58,40 @@ const addOutputsToFed = (tx, outputsToFed) => {
});
};

const pushPegin = async (btcTxHelper, btcPeginTxHash, expectedUtxosCount) => {
const pushPegin = async (btcPeginTxHash, expectedUtxosCount) => {
await waitForBitcoinTxToBeInMempool(btcTxHelper, btcPeginTxHash);
await mineForPeginRegistration(rskTxHelper, btcTxHelper);
await ensurePeginIsRegistered(rskTxHelper, btcPeginTxHash, expectedUtxosCount);
};

const getSendersInfo = async (initialBtcSenderBalancesInBtc) => {
return await Promise.all(initialBtcSenderBalancesInBtc.map(initialBtcSenderBalance => createSenderRecipientInfo(rskTxHelper, btcTxHelper, 'legacy', initialBtcSenderBalance + btcTxHelper.getFee())));
};

const getSendersBtcAddressBalances = async (sendersInfo) => {
return await Promise.all(sendersInfo.map(senderInfo => btcTxHelper.getAddressBalance(senderInfo.btcSenderAddressInfo.address)));
};

const getSendersUtxosInfo = async (sendersInfo, btcSenderAmountsToSendToFed) => {
return await Promise.all(sendersInfo.map((senderInfo, index) => btcTxHelper.selectSpendableUTXOsFromAddress(senderInfo.btcSenderAddressInfo.address, btcSenderAmountsToSendToFed[index])));
};

const getSendersChange = (sendersUtxosInfo) => {
return sendersUtxosInfo.map(senderUtxosInfo => senderUtxosInfo.change - btcTxHelper.getFee());
};

const getSendersPrivateKeys = (sendersInfo) => {
return sendersInfo.map(senderInfo => senderInfo.btcSenderAddressInfo.privateKey);
};

const getTotalAmountToFed = (outputsToFed) => {
return outputsToFed.reduce((total, amount) => total + amount, 0);
};

const getFinalRskRecipientBalances = async (sendersInfo) => {
return await Promise.all(sendersInfo.map(senderInfo => rskTxHelper.getBalance(senderInfo.rskRecipientRskAddressInfo.address)));
};

const testsExpectedToPass = [
{
description: 'should do pegin with one input and one output to the federation',
Expand Down Expand Up @@ -97,8 +125,8 @@ const execute = (description, getRskHost) => {
bridge = getBridge(rskTxHelper.getClient());

federationAddress = await bridge.methods.getFederationAddress().call();

await btcTxHelper.importAddress(federationAddress, 'federation');

await waitAndUpdateBridge(rskTxHelper);
await setupBridgeDonation(rskTxHelpers, btcTxHelper);

Expand All @@ -114,61 +142,67 @@ const execute = (description, getRskHost) => {

const initialFederationAddressBalanceInBtc = Number(await btcTxHelper.getAddressBalance(federationAddress));

const sendersInfo = await Promise.all(initialBtcSenderBalancesInBtc.map(initialBtcSenderBalance => createSenderRecipientInfo(rskTxHelper, btcTxHelper, 'legacy', initialBtcSenderBalance + btcTxHelper.getFee())));
const sendersInfo = await getSendersInfo(initialBtcSenderBalancesInBtc);
const senderInfo1 = sendersInfo[0];

const initialSendersBtcAddressBalances = await Promise.all(sendersInfo.map(senderInfo => btcTxHelper.getAddressBalance(senderInfo.btcSenderAddressInfo.address)));
const sendersUtxosInfo = await Promise.all(sendersInfo.map((senderInfo, index) => btcTxHelper.selectSpendableUTXOsFromAddress(senderInfo.btcSenderAddressInfo.address, btcSenderAmountsToSendToFed[index])));
const sendersChange = sendersUtxosInfo.map(senderUtxosInfo => senderUtxosInfo.change - btcTxHelper.btcConfig.txFee);
const initialSendersBtcAddressBalances = await getSendersBtcAddressBalances(sendersInfo);
const sendersUtxosInfo = await getSendersUtxosInfo(sendersInfo, btcSenderAmountsToSendToFed);
const sendersChange = getSendersChange(sendersUtxosInfo);

const tx = new bitcoinJsLib.Transaction();
addInputs(tx, sendersUtxosInfo.flatMap(senderUtxosInfo => senderUtxosInfo.utxos));
addInputs(tx, sendersUtxosInfo);
addOutputsToFed(tx, outputsToFed);
addChangeOutputs(tx, sendersInfo, sendersChange);

const sendersPrivateKeys = sendersInfo.map(senderInfo => senderInfo.btcSenderAddressInfo.privateKey);
const sendersPrivateKeys = getSendersPrivateKeys(sendersInfo);
const signedTx = await btcTxHelper.nodeClient.signTransaction(tx.toHex(), [], sendersPrivateKeys);

// Act

// Sending the pegin
// Sending the pegin and ensuring the pegin is registered
const btcPeginTxHash = await btcTxHelper.nodeClient.sendTransaction(signedTx);

// Ensuring the pegin is registered
await pushPegin(btcTxHelper, btcPeginTxHash, outputsToFed.length);
await pushPegin(btcPeginTxHash, outputsToFed.length);

// Assert

const isBtcTxHashAlreadyProcessed = await bridge.methods.isBtcTxHashAlreadyProcessed(btcPeginTxHash).call();
expect(isBtcTxHashAlreadyProcessed).to.be.true;

const totalAmountToFed = outputsToFed.reduce((total, amount) => total + amount, 0);
const totalAmountToFed = getTotalAmountToFed(outputsToFed);

const expectedEvent = createExpectedPeginBtcEvent(PEGIN_EVENTS.PEGIN_BTC, senderInfo1.rskRecipientRskAddressInfo.address, btcPeginTxHash, btcToSatoshis(totalAmountToFed), '0');
// The expected pegin_btc event should be emitted
const recipient1RskAddressChecksumed = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(senderInfo1.rskRecipientRskAddressInfo.address));
const expectedEvent = createExpectedPeginBtcEvent(PEGIN_EVENTS.PEGIN_BTC, recipient1RskAddressChecksumed, btcPeginTxHash, btcToSatoshis(totalAmountToFed));
const btcTxHashProcessedHeight = Number(await bridge.methods.getBtcTxHashProcessedHeight(btcPeginTxHash).call());
await findAndCheckPeginBtcEventInBlock(rskTxHelper, btcTxHashProcessedHeight, expectedEvent);
const peginBtcEvent = await findEventInBlock(rskTxHelper, expectedEvent.name, btcTxHashProcessedHeight);
expect(peginBtcEvent).to.be.deep.equal(expectedEvent);

// The federation address should have received the total amount sent by the senders
const finalFederationAddressBalanceInBtc = Number(await btcTxHelper.getAddressBalance(federationAddress));
expect(finalFederationAddressBalanceInBtc).to.be.equal(initialFederationAddressBalanceInBtc + totalAmountToFed);

// The senders should have their balances reduced by the amount sent to the federation and the fee
const finalSendersBtcAddressBalances = await Promise.all(sendersInfo.map(senderInfo => btcTxHelper.getAddressBalance(senderInfo.btcSenderAddressInfo.address)));
finalSendersBtcAddressBalances.forEach((balance, index) => {
expect(Number(btcToSatoshis(balance))).to.be.equal(btcToSatoshis(initialSendersBtcAddressBalances[index]) - btcToSatoshis(btcSenderAmountsToSendToFed[index]) - btcToSatoshis(btcTxHelper.getFee()));
});
const finalSendersBtcAddressBalances = await getSendersBtcAddressBalances(sendersInfo);

for(let i = 0; i < finalSendersBtcAddressBalances.length; i++) {
const actualFinalBalance = Number(btcToSatoshis(finalSendersBtcAddressBalances[i]));
const expectedFinalBalance = Number(btcToSatoshis(initialSendersBtcAddressBalances[i])) - Number(btcToSatoshis(btcSenderAmountsToSendToFed[i])) - Number(btcToSatoshis(btcTxHelper.getFee()));
expect(actualFinalBalance).to.be.equal(expectedFinalBalance);
}

const finalRskRecipientBalances = await Promise.all(sendersInfo.map(senderInfo => rskTxHelper.getBalance(senderInfo.rskRecipientRskAddressInfo.address)));
const finalRskRecipientBalances = await getFinalRskRecipientBalances(sendersInfo);

// Retrieving and removing the first rsk recipient balance since only the first sender should have the amount locked.
const firstRskRecipientBalance = finalRskRecipientBalances.shift();
expect(Number(firstRskRecipientBalance)).to.be.equal(Number(btcToWeis(totalAmountToFed)));

// The other rsk recipients should have their balances unchanged
finalRskRecipientBalances.forEach((balance) => {
expect(Number(balance)).to.be.equal(0);
});

for(let i = 0; i < finalRskRecipientBalances.length; i++) {
const actualFinalBalance = Number(finalRskRecipientBalances[i]);
const expectedFinalBalance = 0;
expect(actualFinalBalance).to.be.equal(expectedFinalBalance);
}

});

});
Expand Down

0 comments on commit d280986

Please sign in to comment.