From 9d7372eaa7559c8d3455601412f0b5bfa32044cd Mon Sep 17 00:00:00 2001 From: jeremy-then Date: Wed, 30 Oct 2024 21:28:39 -0400 Subject: [PATCH 1/4] Adds 'should create multiple pegouts with mixed values same and above minimum' test Rebase --- lib/2wp-utils.js | 7 +- lib/rsk-utils.js | 25 ++++++ lib/tests/2wp.js | 211 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 218 insertions(+), 25 deletions(-) diff --git a/lib/2wp-utils.js b/lib/2wp-utils.js index 9e777b73..19378094 100644 --- a/lib/2wp-utils.js +++ b/lib/2wp-utils.js @@ -59,17 +59,19 @@ const assertRefundUtxosSameAsPeginUtxos = async(rskTxHelper, btcTxHelper, peginT * @param {BN} amountInWeisBN * @param {string} rskFromAddress * @param {boolean} mine If true, mines 1 block after sending the transaction. If false, it will not mine the tx and will return undefined. Defaults to true. - * @returns {web3.eth.TransactionReceipt | undefined} + * @returns {Promise} the rsk tx receipt if `mine` is true, otherwise the tx promise. */ const sendTxToBridge = async (rskTxHelper, amountInWeisBN, rskFromAddress, mine = true) => { + const txPromise = rskTxHelper.sendTransaction({ from: rskFromAddress, to: BRIDGE_ADDRESS, value: amountInWeisBN, gasPrice: TO_BRIDGE_GAS_PRICE, }); + if(!mine) { - return; + return txPromise; } // Wait for the rsk tx to be in the rsk mempool before mining @@ -78,6 +80,7 @@ const sendTxToBridge = async (rskTxHelper, amountInWeisBN, rskFromAddress, mine await mineAndSync(getRskTransactionHelpers()); const result = await txPromise; return result; + }; /** diff --git a/lib/rsk-utils.js b/lib/rsk-utils.js index bddd7409..5f8f7021 100644 --- a/lib/rsk-utils.js +++ b/lib/rsk-utils.js @@ -538,6 +538,30 @@ const getNewFundedRskAddress = async (rskTxHelper, fundingAmountInRbtc = DEFAULT return address; }; +/** + * Waits for the rsk mempool to get `atLeastExpectedCount` txs. Attempting `maxAttempts` times, checking every `waitTimeInMilliseconds`. + * @param {RskTransactionHelper} rskTxHelper + * @param {number} atLeastExpectedCount + * @param {number} waitTimeInMilliseconds defaults to 500 milliseconds + * @param {number} maxAttempts defaults to 20 attempts + * @returns {Promise} + * @throws {Error} if the rsk mempool doesn't get at least `atLeastExpectedCount` txs after `maxAttempts` attempts + */ +const waitForRskMempoolToGetAtLeastThisManyTxs = async (rskTxHelper, atLeastExpectedCount, waitTimeInMilliseconds = 500, maxAttempts = 20) => { + let attempts = 1; + while(attempts <= maxAttempts) { + const rskMempoolTxs = await getRskMempoolTransactionHashes(rskTxHelper); + logger.debug(`[${waitForRskMempoolToGetAtLeastThisManyTxs.name}] rsk mempool txs: ${rskMempoolTxs.length}`); + if(rskMempoolTxs.length >= atLeastExpectedCount) { + logger.debug(`[${waitForRskMempoolToGetAtLeastThisManyTxs.name}] rsk mempool has ${rskMempoolTxs.length} (at least expected was ${atLeastExpectedCount}) txs after ${attempts} attempts`); + return; + } + await wait(waitTimeInMilliseconds); + attempts++; + } + throw new Error(`[${waitForRskMempoolToGetAtLeastThisManyTxs.name}] rsk mempool didn't get at least ${atLeastExpectedCount} txs after ${maxAttempts} attempts`); +}; + module.exports = { mineAndSync, waitForBlock, @@ -558,4 +582,5 @@ module.exports = { getPegoutEventsInBlockRange, setFeePerKb, getNewFundedRskAddress, + waitForRskMempoolToGetAtLeastThisManyTxs, }; diff --git a/lib/tests/2wp.js b/lib/tests/2wp.js index 62cfdadb..f9467933 100644 --- a/lib/tests/2wp.js +++ b/lib/tests/2wp.js @@ -5,7 +5,16 @@ const { getBridge } = require('../precompiled-abi-forks-util'); const { getBtcClient } = require('../btc-client-provider'); const { getRskTransactionHelper, getRskTransactionHelpers } = require('../rsk-tx-helper-provider'); const { satoshisToBtc, btcToSatoshis, satoshisToWeis } = require('@rsksmart/btc-eth-unit-converter'); -const { findEventInBlock, triggerRelease, getPegoutEventsInBlockRange, setFeePerKb, sendTransaction, getNewFundedRskAddress } = require('../rsk-utils'); +const { + findEventInBlock, + triggerRelease, + getPegoutEventsInBlockRange, + setFeePerKb, + sendTransaction, + getRskMempoolTransactionHashes, + getNewFundedRskAddress, + waitForRskMempoolToGetAtLeastThisManyTxs, +} = require('../rsk-utils'); const BridgeTransactionParser = require('@rsksmart/bridge-transaction-parser'); const { PEGIN_REJECTION_REASONS, @@ -28,7 +37,7 @@ const { sendPegin, createExpectedReleaseRequestRejectedEvent, } = require('../2wp-utils'); const { getBtcAddressBalanceInSatoshis } = require('../btc-utils'); -const { ensure0x, removePrefix0x } = require('../utils'); +const { ensure0x, removePrefix0x, wait } = require('../utils'); const { getBridgeState } = require('@rsksmart/bridge-state-data-parser'); const bitcoinJsLib = require('bitcoinjs-lib'); const { deployCallReleaseBtcContract } = require('../contractDeployer'); @@ -905,6 +914,130 @@ const execute = (description, getRskHost) => { }); + it('should create multiple pegouts with mixed values same and above minimum', async () => { + + // Arrange + + const senderRecipientInfo1 = await createSenderRecipientInfo(rskTxHelper, btcTxHelper); + await fundRskAccountThroughAPegin(rskTxHelper, btcTxHelper, senderRecipientInfo1.btcSenderAddressInfo); + + const senderRecipientInfo2 = await createSenderRecipientInfo(rskTxHelper, btcTxHelper); + await fundRskAccountThroughAPegin(rskTxHelper, btcTxHelper, senderRecipientInfo2.btcSenderAddressInfo); + + const senderRecipientInfo3 = await createSenderRecipientInfo(rskTxHelper, btcTxHelper); + await fundRskAccountThroughAPegin(rskTxHelper, btcTxHelper, senderRecipientInfo3.btcSenderAddressInfo); + + const initial2wpBalances = await get2wpBalances(rskTxHelper, btcTxHelper); + + const initialSender1AddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo1.btcSenderAddressInfo.address); + const initialSender2AddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo2.btcSenderAddressInfo.address); + const initialSender3AddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo3.btcSenderAddressInfo.address); + + const pegout1ValueInSatoshis = MINIMUM_PEGOUT_AMOUNT_IN_SATOSHIS; + const pegout2ValueInSatoshis = MINIMUM_PEGOUT_AMOUNT_IN_SATOSHIS + 100_000; + const pegout3ValueInSatoshis = MINIMUM_PEGOUT_AMOUNT_IN_SATOSHIS + 150_000; + const totalPegoutValueInSatoshis = pegout1ValueInSatoshis + pegout2ValueInSatoshis + pegout3ValueInSatoshis; + + const rskMemPoolTxHashes1 = await getRskMempoolTransactionHashes(rskTxHelper); + const initialRskMempoolTxHashesSize = rskMemPoolTxHashes1.length; + + // Act + + const shouldMine = false; + const pegoutTransaction1Promise = sendTxToBridge(rskTxHelper, new BN(satoshisToWeis(pegout1ValueInSatoshis)), senderRecipientInfo1.rskRecipientRskAddressInfo.address, shouldMine); + const pegoutTransaction2Promise = sendTxToBridge(rskTxHelper, new BN(satoshisToWeis(pegout2ValueInSatoshis)), senderRecipientInfo2.rskRecipientRskAddressInfo.address, shouldMine); + const pegoutTransaction3Promise = sendTxToBridge(rskTxHelper, new BN(satoshisToWeis(pegout3ValueInSatoshis)), senderRecipientInfo3.rskRecipientRskAddressInfo.address, shouldMine); + + // Waiting for our 3 txs to reach the mempool before trying to mine them. + 3 because we are sending 3 pegouts. + const atLeastExpectedCount = initialRskMempoolTxHashesSize + 3; + await waitForRskMempoolToGetAtLeastThisManyTxs(rskTxHelper, atLeastExpectedCount); + + // Now our 3 pegout transaction requests will get mined together. + await rskTxHelper.mine(); + + // After mining, we can get the transaction receipts. + const pegoutTransaction1 = await pegoutTransaction1Promise; + const pegoutTransaction2 = await pegoutTransaction2Promise; + const pegoutTransaction3 = await pegoutTransaction3Promise; + + // Assert + + let bridgeStateAfterPegoutCreation; + + // Callback to get the bridge state after the pegout is created + const pegoutCreatedCallback = async () => { + bridgeStateAfterPegoutCreation = await getBridgeState(rskTxHelper.getClient()); + }; + + const callbacks = { + pegoutCreatedCallback + }; + + await triggerRelease(rskTxHelpers, btcTxHelper, callbacks); + + // Checking all the pegout events are emitted and in order + const blockNumberAfterPegoutRelease = await rskTxHelper.getBlockNumber(); + const pegoutsEvents = await getPegoutEventsInBlockRange(rskTxHelper, pegoutTransaction1.blockNumber, blockNumberAfterPegoutRelease); + + // The release_request_received event of the first pegout request + const rskSender1Address = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(senderRecipientInfo1.rskRecipientRskAddressInfo.address)); + const releaseRequestReceivedEvent1 = pegoutsEvents.find(event => event.arguments.sender === rskSender1Address); + assertReleaseRequestReceivedEvent(releaseRequestReceivedEvent1, rskSender1Address, senderRecipientInfo1.btcSenderAddressInfo.address, pegout1ValueInSatoshis); + + // The release_request_received event of the second pegout request + const rskSender2Address = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(senderRecipientInfo2.rskRecipientRskAddressInfo.address)); + const releaseRequestReceivedEvent2 = pegoutsEvents.find(event => event.arguments.sender === rskSender2Address); + assertReleaseRequestReceivedEvent(releaseRequestReceivedEvent2, rskSender2Address, senderRecipientInfo2.btcSenderAddressInfo.address, pegout2ValueInSatoshis); + + // The release_request_received event of the third pegout request + const rskSender3Address = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(senderRecipientInfo3.rskRecipientRskAddressInfo.address)); + const releaseRequestReceivedEvent3 = pegoutsEvents.find(event => event.arguments.sender === rskSender3Address); + assertReleaseRequestReceivedEvent(releaseRequestReceivedEvent3, rskSender3Address, senderRecipientInfo3.btcSenderAddressInfo.address, pegout3ValueInSatoshis); + + const pegoutWaitingForConfirmationWhenPegoutWasCreated = bridgeStateAfterPegoutCreation.pegoutsWaitingForConfirmations[0]; + const btcTransaction = bitcoinJsLib.Transaction.fromHex(pegoutWaitingForConfirmationWhenPegoutWasCreated.btcRawTx); + const pegoutCreationRskTransactionHash = ensure0x(pegoutWaitingForConfirmationWhenPegoutWasCreated.rskTxHash.padStart(64, '0')); + + // Release requested events + const releaseRequestedEvent = pegoutsEvents[3]; + assertReleaseRequestedEvent(releaseRequestedEvent, pegoutCreationRskTransactionHash, btcTransaction.getId(), totalPegoutValueInSatoshis); + + const batchPegoutCreatedEvent = pegoutsEvents[4]; + assertBatchPegoutCreatedEvent(batchPegoutCreatedEvent, btcTransaction.getId(), [pegoutTransaction1.transactionHash, pegoutTransaction2.transactionHash, pegoutTransaction3.transactionHash]); + + // pegout_confirmed event + const pegoutConfirmedEvent = pegoutsEvents[5]; + assertPegoutConfirmedEvent(pegoutConfirmedEvent, btcTransaction.getId(), pegoutWaitingForConfirmationWhenPegoutWasCreated.pegoutCreationBlockNumber); + + // add_signature events + const addSignatureEvents = pegoutsEvents.slice(6, pegoutsEvents.length - 1); + assertAddSignatureEvents(addSignatureEvents, releaseRequestedEvent); + + // release_btc event + const releaseBtcEvent = pegoutsEvents[pegoutsEvents.length - 1]; + assertReleaseBtcEvent(releaseBtcEvent, releaseRequestedEvent); + + await assert2wpBalanceAfterSuccessfulPegout(initial2wpBalances, totalPegoutValueInSatoshis); + + const releaseBtcTransaction = bitcoinJsLib.Transaction.fromHex(removePrefix0x(releaseBtcEvent.arguments.btcRawTransaction)); + + // Asserting actual value received for sender 1 + const finalSenderAddressBalanceInSatoshis1 = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo1.btcSenderAddressInfo.address); + const sender1Utxo = getAddressUtxo(releaseBtcTransaction.outs, senderRecipientInfo1.btcSenderAddressInfo.address); + expect(finalSenderAddressBalanceInSatoshis1).to.be.equal(initialSender1AddressBalanceInSatoshis + sender1Utxo.value); + + // Asserting actual value received for sender 2 + const finalSenderAddressBalanceInSatoshis2 = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo2.btcSenderAddressInfo.address); + const serder2Utxo = getAddressUtxo(releaseBtcTransaction.outs, senderRecipientInfo2.btcSenderAddressInfo.address); + expect(finalSenderAddressBalanceInSatoshis2).to.be.equal(initialSender2AddressBalanceInSatoshis + serder2Utxo.value); + + // Asserting actual value received for sender 3 + const finalSenderAddressBalanceInSatoshis3 = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo3.btcSenderAddressInfo.address); + const serder3Utxo = getAddressUtxo(releaseBtcTransaction.outs, senderRecipientInfo3.btcSenderAddressInfo.address); + expect(finalSenderAddressBalanceInSatoshis3).to.be.equal(initialSender3AddressBalanceInSatoshis + serder3Utxo.value); + + }); + }); }; @@ -1011,6 +1144,44 @@ const assertBtcPeginTxHashProcessed = async (btcPeginTxHash) => { expect(isBtcTxHashAlreadyProcessed).to.be.true; }; +const assertReleaseRequestReceivedEvent = (releaseRequestReceivedEvent, rskSenderAddress, btcRecipientAddress, pegoutValueInSatoshis) => { + expect(releaseRequestReceivedEvent.arguments.sender).to.be.equal(rskSenderAddress); + expect(Number(releaseRequestReceivedEvent.arguments.amount)).to.be.equal(pegoutValueInSatoshis); + expect(releaseRequestReceivedEvent.arguments.btcDestinationAddress).to.be.equal(btcRecipientAddress); +}; + +const assertReleaseRequestedEvent = (releaseRequestedEvent, pegoutCreationRskTransactionHash, btcTxHash, pegoutValueInSatoshis) => { + expect(releaseRequestedEvent.arguments.rskTxHash).to.be.equal(pegoutCreationRskTransactionHash); + expect(removePrefix0x(releaseRequestedEvent.arguments.btcTxHash)).to.be.equal(btcTxHash); + expect(Number(releaseRequestedEvent.arguments.amount)).to.be.equal(pegoutValueInSatoshis); +}; + +const assertBatchPegoutCreatedEvent = (batchPegoutCreatedEvent, btcTxHash, pegoutRequestReceivedTransactionHashes) => { + expect(removePrefix0x(batchPegoutCreatedEvent.arguments.btcTxHash)).to.be.equal(btcTxHash); + const releaseRskTxHashes = batchPegoutCreatedEvent.arguments.releaseRskTxHashes; + const allPegoutRequestReceivedTxHashesAreInBatch = pegoutRequestReceivedTransactionHashes.every(hash => releaseRskTxHashes.includes(removePrefix0x(hash))); + expect(allPegoutRequestReceivedTxHashesAreInBatch).to.be.true; +}; + +const assertPegoutConfirmedEvent = (pegoutConfirmedEvent, btcTxHash, pegoutCreationBlockNumber) => { + expect(removePrefix0x(pegoutConfirmedEvent.arguments.btcTxHash)).to.be.equal(btcTxHash); + expect(pegoutConfirmedEvent.arguments.pegoutCreationRskBlockNumber).to.be.equal(pegoutCreationBlockNumber); +}; + +const assertAddSignatureEvent = (addSignatureEvent, releaseRequestedEvent) => { + expect(addSignatureEvent.arguments.releaseRskTxHash).to.be.equal(releaseRequestedEvent.arguments.rskTxHash); +}; + +const assertAddSignatureEvents = (addSignatureEvents, releaseRequestedEvent) => { + addSignatureEvents.forEach(addSignatureEvent => { + assertAddSignatureEvent(addSignatureEvent, releaseRequestedEvent); + }); +}; + +const assertReleaseBtcEvent = (releaseBtcEvent, releaseRequestedEvent) => { + expect(releaseBtcEvent.arguments.releaseRskTxHash).to.be.equal(releaseRequestedEvent.arguments.rskTxHash); +}; + const assertSuccessfulPegoutEventsAreEmitted = async (pegoutsEvents, pegoutRequestReceivedTransactionHash, senderRecipientInfo, pegoutValueInSatoshis, bridgeStateAfterPegoutCreation) => { const pegoutWaitingForConfirmationWhenPegoutWasCreated = bridgeStateAfterPegoutCreation.pegoutsWaitingForConfirmations[0]; @@ -1019,40 +1190,27 @@ const assertSuccessfulPegoutEventsAreEmitted = async (pegoutsEvents, pegoutReque // release_request_received event const releaseRequestReceivedEvent = pegoutsEvents[0]; - expect(releaseRequestReceivedEvent.arguments.sender).to.be.equal(rskSenderAddress); - expect(Number(releaseRequestReceivedEvent.arguments.amount)).to.be.equal(pegoutValueInSatoshis); - expect(releaseRequestReceivedEvent.arguments.btcDestinationAddress).to.be.equal(senderRecipientInfo.btcSenderAddressInfo.address); + assertReleaseRequestReceivedEvent(releaseRequestReceivedEvent, rskSenderAddress, senderRecipientInfo.btcSenderAddressInfo.address, pegoutValueInSatoshis); // release_requested event const pegoutCreationRskTransactionHash = ensure0x(pegoutWaitingForConfirmationWhenPegoutWasCreated.rskTxHash.padStart(64, '0')); const releaseRequestedEvent = pegoutsEvents[1]; - expect(releaseRequestedEvent.arguments.rskTxHash).to.be.equal(pegoutCreationRskTransactionHash); - expect(removePrefix0x(releaseRequestedEvent.arguments.btcTxHash)).to.be.equal(btcTransaction.getId()); - expect(Number(releaseRequestReceivedEvent.arguments.amount)).to.be.equal(pegoutValueInSatoshis); + assertReleaseRequestedEvent(releaseRequestedEvent, pegoutCreationRskTransactionHash, btcTransaction.getId(), pegoutValueInSatoshis); // batch_pegout_created event const batchPegoutCreatedEvent = pegoutsEvents[2]; - expect(removePrefix0x(batchPegoutCreatedEvent.arguments.btcTxHash)).to.be.equal(btcTransaction.getId()); - expect(batchPegoutCreatedEvent.arguments.releaseRskTxHashes.includes(removePrefix0x(pegoutRequestReceivedTransactionHash))).to.be.true; - + assertBatchPegoutCreatedEvent(batchPegoutCreatedEvent, btcTransaction.getId(), [pegoutRequestReceivedTransactionHash]); // pegout_confirmed event const pegoutConfirmedEvent = pegoutsEvents[3]; - expect(removePrefix0x(pegoutConfirmedEvent.arguments.btcTxHash)).to.be.equal(btcTransaction.getId()); - expect(pegoutConfirmedEvent.arguments.pegoutCreationRskBlockNumber).to.be.equal(pegoutWaitingForConfirmationWhenPegoutWasCreated.pegoutCreationBlockNumber); + assertPegoutConfirmedEvent(pegoutConfirmedEvent, btcTransaction.getId(), pegoutWaitingForConfirmationWhenPegoutWasCreated.pegoutCreationBlockNumber); - // add_signature events - const addSignatureEvent1 = pegoutsEvents[4]; - const addSignatureEvent2 = pegoutsEvents[5]; - const addSignatureEvent3 = pegoutsEvents[6]; - - expect(addSignatureEvent1.arguments.releaseRskTxHash).to.be.equal(releaseRequestedEvent.arguments.rskTxHash); - expect(addSignatureEvent2.arguments.releaseRskTxHash).to.be.equal(releaseRequestedEvent.arguments.rskTxHash); - expect(addSignatureEvent3.arguments.releaseRskTxHash).to.be.equal(releaseRequestedEvent.arguments.rskTxHash); + const addSignatureEvents = pegoutsEvents.slice(4, pegoutsEvents.length - 1); + assertAddSignatureEvents(addSignatureEvents, releaseRequestedEvent); // Final event, release_btc - const releaseBtcEvent = pegoutsEvents[7]; - expect(releaseBtcEvent.arguments.releaseRskTxHash).to.be.equal(releaseRequestedEvent.arguments.rskTxHash); + const releaseBtcEvent = pegoutsEvents[pegoutsEvents.length - 1]; + assertReleaseBtcEvent(releaseBtcEvent, releaseRequestedEvent); }; @@ -1113,6 +1271,13 @@ const getReleaseRequestRejectedEventFromContractCallTxReceipt = (contractCallTxR return releaseRequestRejectedEvent; }; +const getAddressUtxo = (outputs, address) => { + return outputs.find(output => { + const outputAddress = bitcoinJsLib.address.fromOutputScript(output.script, btcTxHelper.btcConfig.network); + return outputAddress === address; + }); +}; + module.exports = { execute, }; From bc9cb0986d32ec1050e63237971605d1b7a8b65a Mon Sep 17 00:00:00 2001 From: jeremy-then Date: Thu, 7 Nov 2024 15:12:58 -0400 Subject: [PATCH 2/4] Renames variable. --- lib/tests/2wp.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tests/2wp.js b/lib/tests/2wp.js index f9467933..abf93d66 100644 --- a/lib/tests/2wp.js +++ b/lib/tests/2wp.js @@ -37,7 +37,7 @@ const { sendPegin, createExpectedReleaseRequestRejectedEvent, } = require('../2wp-utils'); const { getBtcAddressBalanceInSatoshis } = require('../btc-utils'); -const { ensure0x, removePrefix0x, wait } = require('../utils'); +const { ensure0x, removePrefix0x } = require('../utils'); const { getBridgeState } = require('@rsksmart/bridge-state-data-parser'); const bitcoinJsLib = require('bitcoinjs-lib'); const { deployCallReleaseBtcContract } = require('../contractDeployer'); @@ -938,8 +938,8 @@ const execute = (description, getRskHost) => { const pegout3ValueInSatoshis = MINIMUM_PEGOUT_AMOUNT_IN_SATOSHIS + 150_000; const totalPegoutValueInSatoshis = pegout1ValueInSatoshis + pegout2ValueInSatoshis + pegout3ValueInSatoshis; - const rskMemPoolTxHashes1 = await getRskMempoolTransactionHashes(rskTxHelper); - const initialRskMempoolTxHashesSize = rskMemPoolTxHashes1.length; + const rskMemPoolTxHashes = await getRskMempoolTransactionHashes(rskTxHelper); + const initialRskMempoolTxHashesSize = rskMemPoolTxHashes.length; // Act From 1fce5b75c0e3ffca017da375a00b01da2b157076 Mon Sep 17 00:00:00 2001 From: jeremy-then Date: Fri, 8 Nov 2024 17:11:46 -0400 Subject: [PATCH 3/4] Asserting pegout requests in the Bridge. --- lib/btc-utils.js | 5 +++++ lib/tests/2wp.js | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/btc-utils.js b/lib/btc-utils.js index 5cff6947..a9f6acfe 100644 --- a/lib/btc-utils.js +++ b/lib/btc-utils.js @@ -187,6 +187,10 @@ const waitForBitcoinMempoolToGetTxs = async (btcTxHelper, maxAttempts = 3, check return Number(btcToSatoshis(await btcTxHelper.getAddressBalance(btcAddress))); }; + const base58AddressToHexString = (base58Address) => { + return bitcoinJs.address.fromBase58Check(base58Address).hash.toString('hex'); + }; + module.exports = { publicKeyToCompressed, fundAddressAndGetData, @@ -194,4 +198,5 @@ const waitForBitcoinMempoolToGetTxs = async (btcTxHelper, maxAttempts = 3, check waitForBitcoinTxToBeInMempool, waitForBitcoinMempoolToGetTxs, getBtcAddressBalanceInSatoshis, + base58AddressToHexString, }; diff --git a/lib/tests/2wp.js b/lib/tests/2wp.js index abf93d66..75749f4c 100644 --- a/lib/tests/2wp.js +++ b/lib/tests/2wp.js @@ -36,8 +36,8 @@ const { sendPegin, fundRskAccountThroughAPegin, createExpectedReleaseRequestRejectedEvent, } = require('../2wp-utils'); -const { getBtcAddressBalanceInSatoshis } = require('../btc-utils'); -const { ensure0x, removePrefix0x } = require('../utils'); +const { getBtcAddressBalanceInSatoshis, base58AddressToHexString } = require('../btc-utils'); +const { ensure0x, removePrefix0x, wait } = require('../utils'); const { getBridgeState } = require('@rsksmart/bridge-state-data-parser'); const bitcoinJsLib = require('bitcoinjs-lib'); const { deployCallReleaseBtcContract } = require('../contractDeployer'); @@ -962,6 +962,21 @@ const execute = (description, getRskHost) => { // Assert + const bridgeStateAfterPegoutRequestsReceived = await getBridgeState(rskTxHelper.getClient()); + const pegoutRequests = bridgeStateAfterPegoutRequestsReceived.pegoutRequests; + + expect(pegoutRequests.length).to.be.equal(3); + + // They could be in any order, so we need to find them. + const pegoutRequest1 = findPegoutRequest(pegoutRequests, pegoutTransaction1.transactionHash); + const pegoutRequest2 = findPegoutRequest(pegoutRequests, pegoutTransaction2.transactionHash); + const pegoutRequest3 = findPegoutRequest(pegoutRequests, pegoutTransaction3.transactionHash); + + // Assert that the pegout requests are in the Bridge + assertBridgePegoutRequest(pegoutRequest1, base58AddressToHexString(senderRecipientInfo1.btcSenderAddressInfo.address), pegout1ValueInSatoshis, pegoutTransaction1.transactionHash); + assertBridgePegoutRequest(pegoutRequest2, base58AddressToHexString(senderRecipientInfo2.btcSenderAddressInfo.address), pegout2ValueInSatoshis, pegoutTransaction2.transactionHash); + assertBridgePegoutRequest(pegoutRequest3, base58AddressToHexString(senderRecipientInfo3.btcSenderAddressInfo.address), pegout3ValueInSatoshis, pegoutTransaction3.transactionHash); + let bridgeStateAfterPegoutCreation; // Callback to get the bridge state after the pegout is created @@ -1278,6 +1293,22 @@ const getAddressUtxo = (outputs, address) => { }); }; +const assertBridgePegoutRequest = (pegoutRequest, btcDestinationAddressHash160, amountInSatoshis, rskTxHash) => { + expect(pegoutRequest.destinationAddressHash160).to.be.equal(btcDestinationAddressHash160); + expect(Number(pegoutRequest.amountInSatoshis)).to.be.equal(amountInSatoshis); + expect(ensure0x(pegoutRequest.rskTxHash)).to.be.equal(rskTxHash); +}; + +/** + * + * @param {Array} bridgePegoutRequests the pegout requests array from the bridge state + * @param {string} rskTxHash the tx hash of the pegout request + * @returns {PegoutRequest | undefined} the pegout request object from the bridge state, or undefined if not found + */ +const findPegoutRequest = (bridgePegoutRequests, rskTxHash) => { + return bridgePegoutRequests.find(pegoutRequest => ensure0x(pegoutRequest.rskTxHash) === rskTxHash); +}; + module.exports = { execute, }; From bb4a7ebf009021fc9186e7da3699d80f7d6a45b9 Mon Sep 17 00:00:00 2001 From: jeremy-then Date: Mon, 11 Nov 2024 09:36:57 -0400 Subject: [PATCH 4/4] Renames base58AddressToHexString to base58AddressToHash160 --- lib/btc-utils.js | 37 +++++++++++++++++++++---------------- lib/tests/2wp.js | 8 ++++---- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/btc-utils.js b/lib/btc-utils.js index a9f6acfe..5e97e144 100644 --- a/lib/btc-utils.js +++ b/lib/btc-utils.js @@ -181,22 +181,27 @@ const waitForBitcoinMempoolToGetTxs = async (btcTxHelper, maxAttempts = 3, check logger.debug(`[${waitForBitcoinMempoolToGetTxs.name}] The final bitcoin mempool size is ${finalBitcoinMempoolSize}, after ${attempts} attempts. Difference with initial mempool size: ${finalBitcoinMempoolSize - initialBitcoinMempoolSize}.`); return bitcoinMempoolHasTx; - } +} - const getBtcAddressBalanceInSatoshis = async (btcTxHelper, btcAddress) => { - return Number(btcToSatoshis(await btcTxHelper.getAddressBalance(btcAddress))); - }; +const getBtcAddressBalanceInSatoshis = async (btcTxHelper, btcAddress) => { + return Number(btcToSatoshis(await btcTxHelper.getAddressBalance(btcAddress))); +}; - const base58AddressToHexString = (base58Address) => { - return bitcoinJs.address.fromBase58Check(base58Address).hash.toString('hex'); - }; +/** + * converts a base58 bitcoin address to its string hash160 representation + * @param {string} base58Address the bitcoin address in base58 format + * @returns {string} the hash160 representation of the base58 bitcoin address + */ +const base58AddressToHash160 = (base58Address) => { + return bitcoinJs.address.fromBase58Check(base58Address).hash.toString('hex'); +}; - module.exports = { - publicKeyToCompressed, - fundAddressAndGetData, - getBitcoinTransactionsInMempool, - waitForBitcoinTxToBeInMempool, - waitForBitcoinMempoolToGetTxs, - getBtcAddressBalanceInSatoshis, - base58AddressToHexString, - }; +module.exports = { + publicKeyToCompressed, + fundAddressAndGetData, + getBitcoinTransactionsInMempool, + waitForBitcoinTxToBeInMempool, + waitForBitcoinMempoolToGetTxs, + getBtcAddressBalanceInSatoshis, + base58AddressToHash160, +}; diff --git a/lib/tests/2wp.js b/lib/tests/2wp.js index 75749f4c..a5c0a123 100644 --- a/lib/tests/2wp.js +++ b/lib/tests/2wp.js @@ -36,7 +36,7 @@ const { sendPegin, fundRskAccountThroughAPegin, createExpectedReleaseRequestRejectedEvent, } = require('../2wp-utils'); -const { getBtcAddressBalanceInSatoshis, base58AddressToHexString } = require('../btc-utils'); +const { getBtcAddressBalanceInSatoshis, base58AddressToHash160 } = require('../btc-utils'); const { ensure0x, removePrefix0x, wait } = require('../utils'); const { getBridgeState } = require('@rsksmart/bridge-state-data-parser'); const bitcoinJsLib = require('bitcoinjs-lib'); @@ -973,9 +973,9 @@ const execute = (description, getRskHost) => { const pegoutRequest3 = findPegoutRequest(pegoutRequests, pegoutTransaction3.transactionHash); // Assert that the pegout requests are in the Bridge - assertBridgePegoutRequest(pegoutRequest1, base58AddressToHexString(senderRecipientInfo1.btcSenderAddressInfo.address), pegout1ValueInSatoshis, pegoutTransaction1.transactionHash); - assertBridgePegoutRequest(pegoutRequest2, base58AddressToHexString(senderRecipientInfo2.btcSenderAddressInfo.address), pegout2ValueInSatoshis, pegoutTransaction2.transactionHash); - assertBridgePegoutRequest(pegoutRequest3, base58AddressToHexString(senderRecipientInfo3.btcSenderAddressInfo.address), pegout3ValueInSatoshis, pegoutTransaction3.transactionHash); + assertBridgePegoutRequest(pegoutRequest1, base58AddressToHash160(senderRecipientInfo1.btcSenderAddressInfo.address), pegout1ValueInSatoshis, pegoutTransaction1.transactionHash); + assertBridgePegoutRequest(pegoutRequest2, base58AddressToHash160(senderRecipientInfo2.btcSenderAddressInfo.address), pegout2ValueInSatoshis, pegoutTransaction2.transactionHash); + assertBridgePegoutRequest(pegoutRequest3, base58AddressToHash160(senderRecipientInfo3.btcSenderAddressInfo.address), pegout3ValueInSatoshis, pegoutTransaction3.transactionHash); let bridgeStateAfterPegoutCreation;