From 122f384d238e669116a5e2ee9f5d74b6844d7481 Mon Sep 17 00:00:00 2001 From: Vasyl Ivanchuk Date: Mon, 13 Nov 2023 19:30:03 +0200 Subject: [PATCH 1/4] fix: block logs transfers --- .../transfer/default.handler.spec.ts | 20 ++++++++++-- .../transfer/default.handler.ts | 5 ++- .../src/transfer/transfer.service.spec.ts | 31 +++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/worker/src/transfer/extractHandlers/transfer/default.handler.spec.ts b/packages/worker/src/transfer/extractHandlers/transfer/default.handler.spec.ts index 20c96ec742..579e25ef74 100644 --- a/packages/worker/src/transfer/extractHandlers/transfer/default.handler.spec.ts +++ b/packages/worker/src/transfer/extractHandlers/transfer/default.handler.spec.ts @@ -123,18 +123,32 @@ describe("defaultTransferHandler", () => { expect(result.isFeeOrRefund).toBe(true); }); - it("extracts transfer of refund type if from address is a bootloader address", () => { + it("extracts transfer of refund type if from address is a bootloader address and there are transaction details", () => { + const transactionDetails = mock(); log.topics[1] = "0x0000000000000000000000000000000000000000000000000000000000008001"; - const result = defaultTransferHandler.extract(log, blockDetails); + const result = defaultTransferHandler.extract(log, blockDetails, transactionDetails); expect(result.type).toBe(TransferType.Refund); }); - it("adds isFeeOrRefund as true if from address is a bootloader address", () => { + it("extracts transfer of transfer type if from address is a bootloader address and there are no transaction details", () => { log.topics[1] = "0x0000000000000000000000000000000000000000000000000000000000008001"; const result = defaultTransferHandler.extract(log, blockDetails); + expect(result.type).toBe(TransferType.Transfer); + }); + + it("adds isFeeOrRefund as true if from address is a bootloader address and there are transaction details", () => { + const transactionDetails = mock(); + log.topics[1] = "0x0000000000000000000000000000000000000000000000000000000000008001"; + const result = defaultTransferHandler.extract(log, blockDetails, transactionDetails); expect(result.isFeeOrRefund).toBe(true); }); + it("adds isFeeOrRefund as false if from address is a bootloader address and there are no transaction details", () => { + log.topics[1] = "0x0000000000000000000000000000000000000000000000000000000000008001"; + const result = defaultTransferHandler.extract(log, blockDetails); + expect(result.isFeeOrRefund).toBe(false); + }); + it("extracts transfer of transfer type if neither to address nor from address is a bootload address", () => { const result = defaultTransferHandler.extract(log, blockDetails); expect(result.type).toBe(TransferType.Transfer); diff --git a/packages/worker/src/transfer/extractHandlers/transfer/default.handler.ts b/packages/worker/src/transfer/extractHandlers/transfer/default.handler.ts index e14f386a1c..1762bc2df8 100644 --- a/packages/worker/src/transfer/extractHandlers/transfer/default.handler.ts +++ b/packages/worker/src/transfer/extractHandlers/transfer/default.handler.ts @@ -19,7 +19,10 @@ export const defaultTransferHandler: ExtractTransferHandler = { let transferType: TransferType = TransferType.Transfer; if (parsedLog.args.to === utils.BOOTLOADER_FORMAL_ADDRESS) { transferType = TransferType.Fee; - } else if (parsedLog.args.from === utils.BOOTLOADER_FORMAL_ADDRESS) { + } + // if transactionDetails is null it means that this transfer comes from a block with + // no transactions and it is a reward to an operator address, so it's a transfer and not a refund + else if (parsedLog.args.from === utils.BOOTLOADER_FORMAL_ADDRESS && transactionDetails) { transferType = TransferType.Refund; } diff --git a/packages/worker/src/transfer/transfer.service.spec.ts b/packages/worker/src/transfer/transfer.service.spec.ts index 682e70ad48..fe5bc10411 100644 --- a/packages/worker/src/transfer/transfer.service.spec.ts +++ b/packages/worker/src/transfer/transfer.service.spec.ts @@ -53,6 +53,7 @@ import * as addressOutOfRange from "../../test/transactionReceipts/address-out-o import * as logParsingError from "../../test/transactionReceipts/log-parsing-error.json"; import * as noDepositAfterFee from "../../test/transactionReceipts/no-deposit-after-fee.json"; import * as feeWithNoDeposits from "../../test/transactionReceipts/fee-with-no-deposits.json"; +import * as blockWithNoTxsLogs from "../../test/logs/block-with-no-txs-logs.json"; jest.mock("../logger", () => ({ default: { @@ -2285,5 +2286,35 @@ describe("TransferService", () => { expect(result).toStrictEqual(expectedTransfers); }); }); + + describe("block with no transactions", () => { + it("properly saves transfers", async () => { + const blockDate = new Date(); + blockDetails.timestamp = blockDate.getTime() / 1000; + + const expectedTransfers = [ + { + amount: BigNumber.from("0xf22ec29c9c4980"), + blockNumber: 6711853, + from: "0x0000000000000000000000000000000000008001", + isFeeOrRefund: false, + isInternal: true, + logIndex: 0, + timestamp: blockDate, + to: "0xa9232040bf0e0aea2578a5b2243f2916dbfc0a69", + tokenAddress: "0x000000000000000000000000000000000000800a", + tokenType: "ETH", + transactionHash: "0x0000000000000000000000000000000000000000000000000000000000000000", + transactionIndex: 0, + type: "transfer", + }, + ]; + + const result = await transferService.saveTransfers(blockWithNoTxsLogs, blockDetails); + expect(transferRepositoryMock.addMany).toHaveBeenCalledTimes(1); + expect(transferRepositoryMock.addMany).toHaveBeenCalledWith(expectedTransfers); + expect(result).toStrictEqual(expectedTransfers); + }); + }); }); }); From 5eeda07ba9b35a584372038dff1cd969e4be3311 Mon Sep 17 00:00:00 2001 From: Vasyl Ivanchuk Date: Mon, 13 Nov 2023 20:34:45 +0200 Subject: [PATCH 2/4] fix: add missing logs file --- .gitignore | 1 + .../test/logs/block-with-no-txs-logs.json | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 packages/worker/test/logs/block-with-no-txs-logs.json diff --git a/.gitignore b/.gitignore index cf84bf3d88..497bd3e2a4 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ tests/e2e/artifacts/ # Logs logs +!/packages/worker/test/logs/ *.log npm-debug.log* yarn-debug.log* diff --git a/packages/worker/test/logs/block-with-no-txs-logs.json b/packages/worker/test/logs/block-with-no-txs-logs.json new file mode 100644 index 0000000000..fd00518101 --- /dev/null +++ b/packages/worker/test/logs/block-with-no-txs-logs.json @@ -0,0 +1,18 @@ +[ + { + "blockNumber": 6711853, + "blockHash": "0xe9b0940095e6e708deebd75fa0320cad868ec5029f92cf8cc8fb464314f5141e", + "transactionIndex": 0, + "removed": false, + "address": "0x000000000000000000000000000000000000800A", + "data": "0x00000000000000000000000000000000000000000000000000f22ec29c9c4980", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000008001", + "0x000000000000000000000000a9232040bf0e0aea2578a5b2243f2916dbfc0a69" + ], + "transactionHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": 0, + "l1BatchNumber": 76725 + } +] \ No newline at end of file From ee255eda473ed20121dbaa5ec260fe86620bcf88 Mon Sep 17 00:00:00 2001 From: Vasyl Ivanchuk Date: Tue, 14 Nov 2023 11:58:52 +0200 Subject: [PATCH 3/4] fix: add DB migration for empty block transfers --- ...8-SetTransferTypeForEmptyBlockTransfers.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts diff --git a/packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts b/packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts new file mode 100644 index 0000000000..6cd28af03b --- /dev/null +++ b/packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts @@ -0,0 +1,22 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class SetTransferTypeForEmptyBlockTransfers1699955766418 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + WITH "updatedTransferNumbers" AS + ( + UPDATE transfers + SET "type" = 'transfer', "isFeeOrRefund" = false, "isInternal" = true, "updatedAt" = CURRENT_TIMESTAMP + WHERE "transactionHash" IS NULL AND "isInternal" = false + RETURNING number + ) + UPDATE "addressTransfers" + SET "isFeeOrRefund" = false, "isInternal" = true, "updatedAt" = CURRENT_TIMESTAMP + FROM "updatedTransferNumbers" + WHERE "transferNumber" = "updatedTransferNumbers"."number" + `); + } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + public async down(): Promise {} +} From e8f22cb1c0dc15c313fc8a5b157b6426cec57005 Mon Sep 17 00:00:00 2001 From: Vasyl Ivanchuk Date: Tue, 14 Nov 2023 14:15:34 +0200 Subject: [PATCH 4/4] fix: improve DB migration --- .../1699955766418-SetTransferTypeForEmptyBlockTransfers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts b/packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts index 6cd28af03b..530b535dfe 100644 --- a/packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts +++ b/packages/worker/src/migrations/1699955766418-SetTransferTypeForEmptyBlockTransfers.ts @@ -6,12 +6,12 @@ export class SetTransferTypeForEmptyBlockTransfers1699955766418 implements Migra WITH "updatedTransferNumbers" AS ( UPDATE transfers - SET "type" = 'transfer', "isFeeOrRefund" = false, "isInternal" = true, "updatedAt" = CURRENT_TIMESTAMP - WHERE "transactionHash" IS NULL AND "isInternal" = false + SET "type" = 'transfer', "isFeeOrRefund" = false, "isInternal" = true + WHERE "transactionHash" IS NULL RETURNING number ) UPDATE "addressTransfers" - SET "isFeeOrRefund" = false, "isInternal" = true, "updatedAt" = CURRENT_TIMESTAMP + SET "isFeeOrRefund" = false, "isInternal" = true FROM "updatedTransferNumbers" WHERE "transferNumber" = "updatedTransferNumbers"."number" `);