Skip to content

Commit

Permalink
Use pegout_confirmed event to update pegout status
Browse files Browse the repository at this point in the history
From waiting_for_confirmations to waiting_for_signatures.
  • Loading branch information
lserra-iov authored and ronaldsg20 committed Aug 4, 2023
1 parent 8a79578 commit 0037c83
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 82 deletions.
32 changes: 16 additions & 16 deletions src/__tests__/unit/services/pegout-data.processor.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,39 +523,39 @@ describe('Service: PegoutDataProcessor', () => {

const dbPegoutWaitingForConfirmation: PegoutStatusDbDataModel = new PegoutStatusDbDataModel();

const rskBlockHeight = 2869973;
const rskBlockHeightForEnoughConfirmation = rskBlockHeight + 20;
const originatingRskBlockHeight = 2869963;
const currentRskBlockHeight = 2869983;
const pegoutCreationRskBlockHeight = 2869973;

dbPegoutWaitingForConfirmation.rskTxHash = rskTxHash;
dbPegoutWaitingForConfirmation.btcRecipientAddress = 'mpKPLWXnmqjtXyoqi5yRBYgmF4PswMGj55';
dbPegoutWaitingForConfirmation.createdOn = createdOn;
dbPegoutWaitingForConfirmation.originatingRskTxHash = originatingRskTxHash;
dbPegoutWaitingForConfirmation.rskBlockHeight = rskBlockHeight;
dbPegoutWaitingForConfirmation.rskBlockHeight = pegoutCreationRskBlockHeight;
dbPegoutWaitingForConfirmation.rskSenderAddress = '0x3A29282d5144cEa68cb33995Ce82212f4B21ccEc';
dbPegoutWaitingForConfirmation.status = PegoutStatus.WAITING_FOR_CONFIRMATION;
dbPegoutWaitingForConfirmation.btcRawTransaction = btcRawTx1;
dbPegoutWaitingForConfirmation.originatingRskBlockHeight = 2869983;
dbPegoutWaitingForConfirmation.originatingRskBlockHeight = originatingRskBlockHeight;
dbPegoutWaitingForConfirmation.valueRequestedInSatoshis = 521000;

mockedPegoutStatusDataService.getManyWaitingForConfirmationNewest.resolves([dbPegoutWaitingForConfirmation]);

mockedBridgeService.getBridgeState.resolves(bridgeState);
mockedPegoutStatusDataService.getManyWaitingForConfirmationNewestCreatedOnBlock.resolves([dbPegoutWaitingForConfirmation]);

const updateCollectionsEventsArgs = new Map();
updateCollectionsEventsArgs.set('sender', '');
const pegoutConfirmedEventArgs = new Map();
pegoutConfirmedEventArgs.set('btcTxHash', '');
pegoutConfirmedEventArgs.set('pegoutCreationRskBlockNumber', pegoutCreationRskBlockHeight);

const bridgeTransaction: Transaction = {
txHash: rskTxHash,
blockNumber: rskBlockHeightForEnoughConfirmation,
blockNumber: currentRskBlockHeight,
method: {
name: '',
signature: '',
arguments: new Map()
},
events: [{
name: BRIDGE_EVENTS.UPDATE_COLLECTIONS,
signature: '0x1069152f4f916cbf155ee32a695d92258481944edb5b6fd649718fc1b43e515e',
arguments: updateCollectionsEventsArgs
name: BRIDGE_EVENTS.PEGOUT_CONFIRMED,
signature: '',
arguments: pegoutConfirmedEventArgs
}]
}

Expand All @@ -577,14 +577,13 @@ describe('Service: PegoutDataProcessor', () => {
pegoutWithWaitingForSignature.btcRecipientAddress = 'mpKPLWXnmqjtXyoqi5yRBYgmF4PswMGj55';
pegoutWithWaitingForSignature.createdOn = createdOn;
pegoutWithWaitingForSignature.originatingRskTxHash = originatingRskTxHash;
pegoutWithWaitingForSignature.rskBlockHeight = rskBlockHeight;
pegoutWithWaitingForSignature.rskBlockHeight = currentRskBlockHeight;
pegoutWithWaitingForSignature.rskSenderAddress = '0x3A29282d5144cEa68cb33995Ce82212f4B21ccEc';
pegoutWithWaitingForSignature.status = PegoutStatus.WAITING_FOR_SIGNATURE;
pegoutWithWaitingForSignature.btcRawTransaction = btcRawTx1;
pegoutWithWaitingForSignature.originatingRskBlockHeight = 2869983;
pegoutWithWaitingForSignature.originatingRskBlockHeight = originatingRskBlockHeight;
pegoutWithWaitingForSignature.valueRequestedInSatoshis = 521000;

expect(thisService.isMethodAccepted(extendedBridgeTx)).equal(true);
sinon.assert.calledTwice(mockedPegoutStatusDataService.set);
});

Expand Down Expand Up @@ -697,6 +696,7 @@ describe('Service: PegoutDataProcessor', () => {
getManyWaitingForSignaturesNewest: sinon.stub(),
getManyByRskTxHashes: sinon.stub(),
getManyByBtcRawTxInputsHashNewest: sinon.stub(),
getManyWaitingForConfirmationNewestCreatedOnBlock: sinon.stub(),
getById: sinon.stub(),
getMany: sinon.stub(),
delete: sinon.stub(),
Expand Down
1 change: 1 addition & 0 deletions src/models/types/bridge-transaction-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export interface ExtendedBridgeEvent extends BridgeEvent{
senderBtcAddress: string;
releaseRskTxHashes: string;
releaseRskTxHash: string;
pegoutCreationRskBlockNumber: number;
};
}
101 changes: 36 additions & 65 deletions src/services/pegout-data.processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,18 @@ export class PegoutDataProcessor implements FilteredBridgeTransactionProcessor {
await this.processIndividualPegout(extendedBridgeTx);
}

// Pegout confirmed and waiting for signatures
if(this.hasPegoutConfirmedEvent(events)) {
this.logger.trace('[process] found a pegout_confirmed event. Processing...');
await this.processPegoutConfirmedStatus(extendedBridgeTx);
}

// Pegout fully processed
if(this.hasReleaseBtcEvent(events)) {
this.logger.trace('[process] found a release_btc event. Processing...');
return await this.processSignedStatusByRtx(extendedBridgeTx);
}

// Update collections is used as a trigger for pegouts that may have been confirmed and should now be waiting for signatures
if(this.hasUpdateCollectionsEvent(events)) {
this.logger.trace('[process] Processing waiting for signature using the update collections event.');
await this.processWaitingForSignaturesStatus(extendedBridgeTx);
}

} catch (e) {
this.logger.error(`[process] error processing pegout: ${e}`);
}
Expand Down Expand Up @@ -112,6 +112,10 @@ export class PegoutDataProcessor implements FilteredBridgeTransactionProcessor {
return events.some(event => event.name === BRIDGE_EVENTS.BATCH_PEGOUT_CREATED);
}

private hasPegoutConfirmedEvent(events: BridgeEvent[]): boolean {
return events.some(event => event.name === BRIDGE_EVENTS.PEGOUT_CONFIRMED);
}

private async processSignedStatusByRtx(extendedBridgeTx: ExtendedBridgeTx): Promise<void> {
const events: ExtendedBridgeEvent[] = extendedBridgeTx.events as ExtendedBridgeEvent[];
const releaseBTCEvent = events.find(event => event.name === BRIDGE_EVENTS.RELEASE_BTC);
Expand Down Expand Up @@ -158,9 +162,7 @@ export class PegoutDataProcessor implements FilteredBridgeTransactionProcessor {
newPegoutStatus.rskTxHash = `${extendedBridgeTx.txHash}___${thePegout.batchPegoutIndex}`;

this.logPegoutData(newPegoutStatus);
this.logger.trace(`[processSignedStatusByRtx] PegOut being released
with amount in weis: ${(await this.getTxFromRskTransaction(originatingRskTxHash)).valueInWeis}`);

this.logger.trace(`[processSignedStatusByRtx] PegOut being released`);
try {
thePegout.isNewestStatus = false;
await this.save(thePegout);
Expand Down Expand Up @@ -215,8 +217,7 @@ export class PegoutDataProcessor implements FilteredBridgeTransactionProcessor {
newClonedPegoutStatus.batchPegoutRskTxHash = extendedBridgeTx.txHash;

this.logPegoutData(newClonedPegoutStatus);
this.logger.trace(`[processBatchPegouts] PegOut waiting for confirmations
with amount in weis: ${(await this.getTxFromRskTransaction(originatingRskTxHash)).valueInWeis}`);
this.logger.trace(`[processBatchPegouts] PegOut waiting for confirmations with amount in weis: ${(await this.getTxFromRskTransaction(originatingRskTxHash)).valueInWeis}`);

await this.addBatchValueInSatoshisToBeReceivedAndFee(newClonedPegoutStatus, extendedBridgeTx.txHash, extendedBridgeTx.blockNumber);

Expand Down Expand Up @@ -266,61 +267,32 @@ export class PegoutDataProcessor implements FilteredBridgeTransactionProcessor {
return sha256(concatenatedBtcTxInputHashes);
}

private async processWaitingForSignaturesStatus(extendedBridgeTx: ExtendedBridgeTx): Promise<void> {
private async processPegoutConfirmedStatus(extendedBridgeTx: ExtendedBridgeTx): Promise<void> {
const currentBlockHeight = extendedBridgeTx.blockNumber;
const rskMaximumConfirmation = Number(process.env.RSK_PEGOUT_MINIMUM_CONFIRMATIONS);

this.logger.trace(`[processWaitingForSignaturesStatus] currentBlockHeight: ${currentBlockHeight}`);

const dbPegoutsWaitingForConfirmations = await this.pegoutStatusDataService.getManyWaitingForConfirmationNewest();
this.logger.trace(`[processWaitingForSignaturesStatus] number of pegouts waiting for confirmations: ${dbPegoutsWaitingForConfirmations.length}`);

const dbPegoutsWithEnoughConfirmations: PegoutStatusDbDataModel[] = dbPegoutsWaitingForConfirmations.filter(dbPegout => {
const blockHeightDiff = currentBlockHeight - dbPegout.rskBlockHeight;
return blockHeightDiff >= rskMaximumConfirmation;
});
this.logger.trace(`[processWaitingForSignaturesStatus] number of pegouts confirmed: ${dbPegoutsWithEnoughConfirmations.length}`);

// TODO: this is most likely incorrect. The processor is syncing so the state up to this point is what we get from the tx itself

// const bridgeState = await this.bridgeService.getBridgeState();
// const pegoutsWaitingForConfirmationMap = bridgeState.pegoutsWaitingForConfirmations
// .reduce((accumulator, pegout) => accumulator.set(pegout.rskTxHash, pegout), new Map<string, PegoutWaitingConfirmation>());
// if(pegoutsWaitingForConfirmationMap.size === 0) {
// this.logger.trace(`[processWaitingForSignaturesStatus] no transactions in waiting for confirmation in the bridge state.`);
// // If none of the pegouts in the db waiting for confirmation are found in the bridge state,
// // it means the were already moved further. Setting them to the next status, waiting for signatures.
// return await this.saveManyAsWaitingForSignature(dbPegoutsWithEnoughConfirmations);
// }
// const pegoutsWaitingForSignatures = dbPegoutsWithEnoughConfirmations.reduce((accumulator: Array<PegoutStatusDbDataModel>, dbPegoutWaitingForSignature: PegoutStatusDbDataModel) => {
// const rskTxHash = remove0x(dbPegoutWaitingForSignature.rskTxHash);
// const pegoutStillInWaitingForConfirmation = pegoutsWaitingForConfirmationMap.get(rskTxHash);
// if(!pegoutStillInWaitingForConfirmation) {
// accumulator.push(dbPegoutWaitingForSignature);
// }
// return accumulator;
// }, []);
try {
let index = 0;
for (let oldPegoutStatus of dbPegoutsWithEnoughConfirmations) {
const newPegoutStatus: PegoutStatusDbDataModel = PegoutStatusDbDataModel.clonePegoutStatusInstance(oldPegoutStatus);
newPegoutStatus.setRskTxInformation(extendedBridgeTx);
newPegoutStatus.rskTxHash = `${extendedBridgeTx.txHash}__${index}`;
newPegoutStatus.isNewestStatus = true;
newPegoutStatus.status = PegoutStatus.WAITING_FOR_SIGNATURE;
oldPegoutStatus.isNewestStatus = false;
await this.save(oldPegoutStatus);
await this.save(newPegoutStatus);
index++;

const originatingRskTxHash = oldPegoutStatus.originatingRskTxHash;
this.logger.trace(`[processPegoutConfirmedStatus] currentBlockHeight: ${currentBlockHeight}`);
const pegoutConfirmedEvent = extendedBridgeTx.events.find(event => event.name === BRIDGE_EVENTS.PEGOUT_CONFIRMED) as ExtendedBridgeEvent;
const { pegoutCreationRskBlockNumber } = pegoutConfirmedEvent.arguments;
this.logger.trace(`[processPegoutConfirmedStatus] pegoutCreationRskBlockNumber: ${pegoutCreationRskBlockNumber}`);
const dbPegoutsWaitingForConfirmations = await this.pegoutStatusDataService.getManyWaitingForConfirmationNewestCreatedOnBlock(pegoutCreationRskBlockNumber);
this.logger.trace(`[processPegoutConfirmedStatus] number of pegouts waiting for confirmations: ${dbPegoutsWaitingForConfirmations.length}`);
return this.changePegoutsToWaitingForSignatures(dbPegoutsWaitingForConfirmations, extendedBridgeTx);
}

this.logPegoutData(newPegoutStatus);
this.logger.trace(`[processWaitingForSignaturesStatus] PegOut waiting for signatures
with amount in weis: ${(await this.getTxFromRskTransaction(originatingRskTxHash)).valueInWeis}`);
private async changePegoutsToWaitingForSignatures(dbPegoutsWaitingForConfirmations: PegoutStatusDbDataModel[], extendedBridgeTx: ExtendedBridgeTx) {
let index = 0;
for (let oldStatus of dbPegoutsWaitingForConfirmations) {
const newStatus = PegoutStatusDbDataModel.clonePegoutStatusInstance(oldStatus);
newStatus.setRskTxInformation(extendedBridgeTx);
newStatus.rskTxHash = `${extendedBridgeTx.txHash}__${index}`;
newStatus.isNewestStatus = true;
newStatus.status = PegoutStatus.WAITING_FOR_SIGNATURE;
oldStatus.isNewestStatus = false;
try {
await this.saveMany([oldStatus, newStatus]);
} catch (e) {
this.logger.warn('[changePegoutsToWaitingForSignatures] There was a problem with the storage', e);
}
} catch (e) {
this.logger.warn(`[processWaitingForSignaturesStatus] Error writing to storage`);
index++;
}
}

Expand Down Expand Up @@ -389,8 +361,7 @@ export class PegoutDataProcessor implements FilteredBridgeTransactionProcessor {
});

if(!output) {
this.logger.debug(`[addValueInSatoshisToBeReceivedAndFee] did not find
an output containing the btcRecipientAddress ${pegoutStatus.btcRecipientAddress}.`);
this.logger.debug(`[addValueInSatoshisToBeReceivedAndFee] did not find an output containing the btcRecipientAddress ${pegoutStatus.btcRecipientAddress}.`);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface PegoutStatusDataService extends GenericDataService<PegoutStatus
getLastByOriginatingRskTxHash(originatingRskTxHash: string): Promise<PegoutStatusDbDataModel | null>;
getLastByOriginatingRskTxHashNewest(originatingRskTxHash: string): Promise<PegoutStatusDbDataModel | null>;
getManyWaitingForConfirmationNewest(): Promise<PegoutStatusDbDataModel[]>;
getManyWaitingForConfirmationNewestCreatedOnBlock(block: number): Promise<PegoutStatusDbDataModel[]>;
getManyWaitingForSignaturesNewest(): Promise<PegoutStatusDbDataModel[]>;
getManyByRskTxHashes(originatingRskTxHashes: Array<string>): Promise<PegoutStatusDbDataModel[]>;
getManyByBtcRawTxInputsHashNewest(btcRawTxInputsHash: string): Promise<PegoutStatusDbDataModel[]>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ export class PegoutStatusMongoDbDataService extends MongoDbDataService<PegoutSta
return pegoutsDocuments.map(PegoutStatusDbDataModel.clonePegoutStatusInstance);
}

public async getManyWaitingForConfirmationNewestCreatedOnBlock(block: number): Promise<PegoutStatusDbDataModel[]> {
const pegoutsDocuments = await this.getConnector()
.find({status: PegoutStatus.WAITING_FOR_CONFIRMATION, isNewestStatus: true, rskBlockHeight: block})
.exec();
return pegoutsDocuments.map(PegoutStatusDbDataModel.clonePegoutStatusInstance);
}

public async getManyWaitingForSignaturesNewest(): Promise<PegoutStatusDbDataModel[]> {
const pegoutsDocuments = await this.getConnector()
.find({status: PegoutStatus.WAITING_FOR_SIGNATURE, isNewestStatus: true})
Expand Down
3 changes: 2 additions & 1 deletion src/utils/bridge-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export enum BRIDGE_EVENTS {
RELEASE_REQUEST_RECEIVED = 'release_request_received',
RELEASE_REQUEST_REJECTED = 'release_request_rejected',
ADD_SIGNATURE = 'add_signature',
BATCH_PEGOUT_CREATED = 'batch_pegout_created'
BATCH_PEGOUT_CREATED = 'batch_pegout_created',
PEGOUT_CONFIRMED = 'pegout_confirmed'
};

export function getBridgeSignature(methodOrEvent: BRIDGE_METHODS | BRIDGE_EVENTS): string {
Expand Down

0 comments on commit 0037c83

Please sign in to comment.