From 27f37a143deed74b721bcb3c33cf4d347d358078 Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Mon, 10 Jun 2024 15:36:37 -0400 Subject: [PATCH] - Add pegout transaction created event assertions for rejected pegin test cases - Moved logic to decode and encode utxo outpoint values to a util function. - Moved pegout event names to a constant file. --- lib/2wp-utils.js | 22 +++++++++++++++++++++- lib/constants.js | 10 ++++++++++ lib/tests/2wp.js | 30 +++++++++++------------------- lib/varint.js | 23 ++++++++++++++++++++++- tests/02_00_05-2wp_version1.js | 12 ++++++++++-- 5 files changed, 74 insertions(+), 23 deletions(-) diff --git a/lib/2wp-utils.js b/lib/2wp-utils.js index 0db45a40..6c209751 100644 --- a/lib/2wp-utils.js +++ b/lib/2wp-utils.js @@ -7,7 +7,7 @@ const { waitForRskMempoolToGetNewTxs, waitAndUpdateBridge } = require('./rsk-utils'); -const { retryWithCheck } = require('./utils'); +const { retryWithCheck, removePrefix0x } = require('./utils'); const { waitForBitcoinTxToBeInMempool, waitForBitcoinMempoolToGetTxs } = require('./btc-utils'); const { getBridge, getLatestActiveForkName } = require('./precompiled-abi-forks-util'); const { getBridgeState } = require('@rsksmart/bridge-state-data-parser'); @@ -17,6 +17,9 @@ const peginVerifier = require('pegin-address-verificator'); const { getRskTransactionHelpers } = require('../lib/rsk-tx-helper-provider'); const { WHITELIST_CHANGE_PK, WHITELIST_CHANGE_ADDR} = require('../lib/assertions/whitelisting'); const { getLogger } = require('../logger'); +const rskUtils = require("./rsk-utils"); +const {PEGOUT_EVENTS} = require("./constants"); +const {encodeOutpointValuesAsMap, decodeOutpointValues} = require("./varint"); const BTC_TO_RSK_MINIMUM_CONFIRMATIONS = 3; const TO_BRIDGE_GAS_PRICE = 2; @@ -25,6 +28,22 @@ const MIN_PEGOUT_VALUE_IN_RBTC = 0.0025; const logger = getLogger(); +const findPegoutCreatedEventAndAssertRefundUtxo = async(rskTxHelper, btcTxHelper, refundAddress, fromBlock, toBlock, amountSentInSatoshis) => { + const refundAddressUtxos = await btcTxHelper.getUtxos(refundAddress); + const refundTxHash = refundAddressUtxos[0].txid; + + const pegoutTransactionCreatedEvent = await rskUtils.findEventInBlock(rskTxHelper, PEGOUT_EVENTS.PEGOUT_TRANSACTION_CREATED, refundAddress, toBlock, (event) => { + return event.arguments.btcTxHash === refundTxHash; + }); + + expect(pegoutTransactionCreatedEvent).to.not.be.null; + expect(pegoutTransactionCreatedEvent.arguments.btcTxHash).to.equal(refundTxHash); + const encodedUtxoOutpointValues = Buffer.from(removePrefix0x(pegoutTransactionCreatedEvent.arguments.utxoOutpointValues), 'hex'); + const federationUtxoValues = encodeOutpointValuesAsMap({ "valueInSatoshis": Number(btcEthUnitConverter.btcToSatoshis(amountSentInSatoshis))}); + const outpointValues = decodeOutpointValues(encodedUtxoOutpointValues); + expect(outpointValues.every(value => value in federationUtxoValues)).to.be.true; +} + /** * * @param {RskTransactionHelper} rskTxHelper @@ -230,6 +249,7 @@ const disableWhitelisting = async (rskTxHelper, btcTxHelper, blockDelay = 1) => module.exports = { sendTxToBridge, assertRefundUtxosSameAsPeginUtxos, + findPegoutCreatedEventAndAssertRefundUtxo, createPegoutRequest, sendPegin, ensurePeginIsRegistered, diff --git a/lib/constants.js b/lib/constants.js index 9baeba79..104a9a4f 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -46,6 +46,15 @@ const PEGIN_REJECTION_REASONS = { PEGIN_V1_INVALID_PAYLOAD_REASON: '4' }; +const PEGOUT_EVENTS = { + RELEASE_REQUEST_RECEIVED: "release_request_received", + RELEASE_REQUEST_REJECTED: "release_request_rejected", + RELEASE_REQUESTED: "release_requested", + BATCH_PEGOUT_CREATED: "batch_pegout_created", + PEGOUT_TRANSACTION_CREATED: "pegout_transaction_created", + PEGOUT_CONFIRMED: "pegout_confirmed" +} + module.exports = { KEY_TYPE_BTC, KEY_TYPE_RSK, @@ -63,4 +72,5 @@ module.exports = { GENESIS_FEDERATION_REDEEM_SCRIPT, FEDERATION_ACTIVATION_AGE, PEGIN_REJECTION_REASONS, + PEGOUT_EVENTS }; diff --git a/lib/tests/2wp.js b/lib/tests/2wp.js index 93efcb42..38234d57 100644 --- a/lib/tests/2wp.js +++ b/lib/tests/2wp.js @@ -10,8 +10,9 @@ const { getDerivedRSKAddressInformation } = require('@rsksmart/btc-rsk-derivatio const btcEthUnitConverter = require('@rsksmart/btc-eth-unit-converter'); const { sendTxToBridge, sendPegin, ensurePeginIsRegistered, donateToBridge } = require('../2wp-utils'); const { waitAndUpdateBridge } = require('../rsk-utils'); -const {VarInt} = require("../varint"); +const { decodeOutpointValues, encodeOutpointValuesAsMap } = require("../varint"); const {getBridgeState} = require("@rsksmart/bridge-state-data-parser"); +const {PEGOUT_EVENTS} = require("../constants"); const DONATION_AMOUNT = 250; const REJECTED_REASON = 1; @@ -153,7 +154,7 @@ const execute = (description, getRskHost) => { const isIris300AlreadyActive = await Runners.common.forks.iris300.isAlreadyActive(); if (isIris300AlreadyActive) { - const pegoutRequestReceivedEvent = await rskUtils.findEventInBlock(rskTxHelper, 'release_request_received'); + const pegoutRequestReceivedEvent = await rskUtils.findEventInBlock(rskTxHelper, PEGOUT_EVENTS.RELEASE_REQUEST_RECEIVED); expect(pegoutRequestReceivedEvent).to.not.be.null; const btcDestinationAddress = pegoutRequestReceivedEvent.arguments.btcDestinationAddress; expect(pegoutRequestReceivedEvent.arguments.sender.toLowerCase()).to.equal(ensure0x(recipientRskAddressInfo.address)); @@ -169,43 +170,34 @@ const execute = (description, getRskHost) => { const pegoutCreatedValidations = async (localRskTxHelper) => { const isPapyrus200AlreadyActive = await Runners.common.forks.papyrus200.isAlreadyActive(); if (isPapyrus200AlreadyActive) { - const pegoutRequestedEvent = await rskUtils.findEventInBlock(localRskTxHelper, 'release_requested'); + const pegoutRequestedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.RELEASE_REQUESTED); expect(pegoutRequestedEvent).to.not.be.null; expect(Number(pegoutRequestedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); } const isHop400AlreadyActive = await Runners.common.forks.hop400.isAlreadyActive(); if (isHop400AlreadyActive) { - const batchPegoutCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, 'batch_pegout_created'); + const batchPegoutCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.BATCH_PEGOUT_CREATED); expect(batchPegoutCreatedEvent).to.not.be.null; expect(batchPegoutCreatedEvent.arguments.releaseRskTxHashes.includes(pegoutTransaction.transactionHash)).to.be.true; } const isLovell700AlreadyActive = await Runners.common.forks.lovell700.isAlreadyActive(); if (isLovell700AlreadyActive) { - const pegoutTransactionCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, 'pegout_transaction_created'); + const pegoutTransactionCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.PEGOUT_TRANSACTION_CREATED); expect(pegoutTransactionCreatedEvent).to.not.be.null; const encodedUtxoOutpointValues = Buffer.from(removePrefix0x(pegoutTransactionCreatedEvent.arguments.utxoOutpointValues), 'hex'); - const federationUtxoValues = activeFederationUtxosBeforePegout.reduce((map, utxo) => { - map[utxo.valueInSatoshis] = Buffer.from(new VarInt(utxo.valueInSatoshis).encode()).toString("hex"); - return map; - }, {}); + const federationUtxoValues = encodeOutpointValuesAsMap(activeFederationUtxosBeforePegout); - let offset = 0; - let idx = 0; - while (encodedUtxoOutpointValues.length > offset) { - let utxoOutpointValue = new VarInt(encodedUtxoOutpointValues, offset); - expect(utxoOutpointValue.value in federationUtxoValues).to.be.true + const outpointValues = decodeOutpointValues(encodedUtxoOutpointValues); - offset += utxoOutpointValue.getSizeInBytes(); - idx++; - } + expect(outpointValues.every(value => value in federationUtxoValues)).to.be.true; } }; const pegoutConfirmedValidations = async (localRskTxHelper) => { if (isFingerroot500AlreadyActive) { - const pegoutConfirmedEvent = await rskUtils.findEventInBlock(localRskTxHelper, 'pegout_confirmed'); + const pegoutConfirmedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.PEGOUT_CONFIRMED); expect(pegoutConfirmedEvent).to.not.be.null; } }; @@ -243,7 +235,7 @@ const execute = (description, getRskHost) => { const pegoutTransaction = await sendTxToBridge(rskTxHelper, PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC, recipientRskAddressInfo.address); const isIris300AlreadyActive = await Runners.common.forks.iris300.isAlreadyActive(); if (isIris300AlreadyActive) { - const pegoutRejectedEvent = await rskUtils.findEventInBlock(rskTxHelper, 'release_request_rejected'); + const pegoutRejectedEvent = await rskUtils.findEventInBlock(rskTxHelper, PEGOUT_EVENTS.RELEASE_REQUEST_REJECTED); expect(pegoutRejectedEvent).to.not.be.null; const pegoutValueInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC)); expect(Number(pegoutRejectedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); diff --git a/lib/varint.js b/lib/varint.js index bed97008..24d56e65 100644 --- a/lib/varint.js +++ b/lib/varint.js @@ -63,4 +63,25 @@ class VarInt { } } -module.exports = { VarInt }; +const decodeOutpointValues = (encodedUtxoOutpointValues) => { + let offset = 0; + let idx = 0; + const outpointValues = []; + while (encodedUtxoOutpointValues.length > offset) { + let utxoOutpointValue = new VarInt(encodedUtxoOutpointValues, offset); + outpointValues.push(utxoOutpointValue.value); + offset += utxoOutpointValue.getSizeInBytes(); + idx++; + } + return outpointValues; +} + +const encodeOutpointValuesAsMap = (utxos) => { + const encodeOutpointValues = utxos.reduce((map, utxo) => { + map[utxo.valueInSatoshis] = Buffer.from(new VarInt(utxo.valueInSatoshis).encode()).toString("hex"); + return map; + }, {}); + return encodeOutpointValues; +} + +module.exports = { VarInt, decodeOutpointValues, encodeOutpointValuesAsMap }; diff --git a/tests/02_00_05-2wp_version1.js b/tests/02_00_05-2wp_version1.js index 159a468c..dad40154 100644 --- a/tests/02_00_05-2wp_version1.js +++ b/tests/02_00_05-2wp_version1.js @@ -1,7 +1,9 @@ const { expect } = require('chai'); const peginVerifier = require('pegin-address-verificator'); const rskUtils = require('../lib/rsk-utils'); -const { sendPegin, ensurePeginIsRegistered, assertRefundUtxosSameAsPeginUtxos } = require('../lib/2wp-utils'); +const { sendPegin, ensurePeginIsRegistered, assertRefundUtxosSameAsPeginUtxos, + findPegoutCreatedEventAndAssertRefundUtxo +} = require('../lib/2wp-utils'); const { getBtcClient } = require('../lib/btc-client-provider'); const { getRskTransactionHelpers } = require('../lib/rsk-tx-helper-provider'); const { getDerivedRSKAddressInformation } = require('@rsksmart/btc-rsk-derivation'); @@ -9,7 +11,7 @@ const btcEthUnitConverter = require('@rsksmart/btc-eth-unit-converter'); const { ensure0x } = require('../lib/utils'); const { PEGIN_REJECTION_REASONS: { PEGIN_V1_INVALID_PAYLOAD_REASON } - } = require('../lib/constants'); +} = require('../lib/constants'); const AMOUNT_TO_LOCK_IN_BTC = 2; @@ -163,6 +165,8 @@ describe('Lock funds using peg-in protocol version 1', () => { expect(rejectedPeginEvent.arguments.btcTxHash).to.equal(peginBtcTxHashWith0xPrefix); expect(rejectedPeginEvent.arguments.reason).to.equal(PEGIN_V1_INVALID_PAYLOAD_REASON); + const amountSentInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(AMOUNT_TO_LOCK_IN_BTC)); + await findPegoutCreatedEventAndAssertRefundUtxo(rskTxHelper, btcTxHelper, senderAddressInformation.address, searchRejectedPeginEventFromBlock, latestBlock, amountSentInSatoshis); }); it('should lock with multiple OP_RETURN outputs but only one for RSK', async () => { @@ -239,6 +243,8 @@ describe('Lock funds using peg-in protocol version 1', () => { expect(rejectedPeginEvent.arguments.btcTxHash).to.equal(peginBtcTxHashWith0xPrefix); expect(rejectedPeginEvent.arguments.reason).to.equal(PEGIN_V1_INVALID_PAYLOAD_REASON); + const amountSentInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(AMOUNT_TO_LOCK_IN_BTC)); + await findPegoutCreatedEventAndAssertRefundUtxo(rskTxHelper, btcTxHelper, peginBtcTxHash, senderAddressInformation.address, searchRejectedPeginEventFromBlock, latestBlock, amountSentInSatoshis); }); it('should refund lock with OP_RETURN output for RSK with invalid version number', async () => { @@ -293,5 +299,7 @@ describe('Lock funds using peg-in protocol version 1', () => { expect(rejectedPeginEvent.arguments.btcTxHash).to.equal(peginBtcTxHashWith0xPrefix); expect(rejectedPeginEvent.arguments.reason).to.equal(PEGIN_V1_INVALID_PAYLOAD_REASON); + const amountSentInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(AMOUNT_TO_LOCK_IN_BTC)); + await findPegoutCreatedEventAndAssertRefundUtxo(rskTxHelper, btcTxHelper, peginBtcTxHash, senderAddressInformation.address, searchRejectedPeginEventFromBlock, latestBlock, amountSentInSatoshis); }); });