Skip to content

Commit

Permalink
Feat/673 add events filters to the postman (#683)
Browse files Browse the repository at this point in the history
* feat: add event filters options to the postman

* fix: update package lock file

* fix: update postman params and event filtering

* fix: update filters format

* fix: update .env.sample

* fix: clean return condition in utility functions regarding events filtering

* fix: change calldata function interface for testing
  • Loading branch information
VGau authored Feb 17, 2025
1 parent d50e814 commit 12a5c33
Show file tree
Hide file tree
Showing 13 changed files with 560 additions and 44 deletions.
30 changes: 14 additions & 16 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion postman/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,15 @@ POSTGRES_DB=postman_db
DB_CLEANER_ENABLED=false
DB_CLEANING_INTERVAL=10000
DB_DAYS_BEFORE_NOW_TO_DELETE=1
ENABLE_LINEA_ESTIMATE_GAS=false
ENABLE_LINEA_ESTIMATE_GAS=false

# Optional event filter params
L1_EVENT_FILTER_FROM_ADDRESS=<FROM_ADDRESS>
L1_EVENT_FILTER_TO_ADDRESS=<TO_ADDRESS>
L1_EVENT_FILTER_CALLDATA=<criteria>
L1_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE=<FUNCTION_INTERFACE>

L2_EVENT_FILTER_FROM_ADDRESS=<FROM_ADDRESS>
L2_EVENT_FILTER_TO_ADDRESS=<TO_ADDRESS>
L2_EVENT_FILTER_CALLDATA=<criteria>
L2_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE=<FUNCTION_INTERFACE>
22 changes: 21 additions & 1 deletion postman/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ All messages are stored in a configurable Postgres DB.
- `L1_LISTENER_BLOCK_CONFIRMATION`: Required block confirmations
- `L1_MAX_BLOCKS_TO_FETCH_LOGS`: Maximum blocks to fetch in one request
- `L1_MAX_GAS_FEE_ENFORCED`: Enable/disable gas fee enforcement
- `L1_EVENT_FILTER_FROM_ADDRESS`: Filter events using a from address
- `L1_EVENT_FILTER_TO_ADDRESS`: Filter events using a to address
- `L1_EVENT_FILTER_CALLDATA`: MessageSent event calldata filtering criteria expression. See [Filtrex repo](https://github.com/joewalnes/filtrex/tree/master).
<br>
You can filter by the calldata field:
<br>

Example:
`calldata.funcSignature == "0x6463fb2a" and calldata.params.messageNumber == 85804`,
- `L1_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE`: Calldata data function interface following this format: `"function transfer(address to, uint256 amount)"`. Make sure you specify parameters names in order to use syntax like `calldata.params.messageNumber`.

#### L2 Configuration
- `L2_RPC_URL`: Linea node RPC endpoint
Expand All @@ -39,6 +49,16 @@ All messages are stored in a configurable Postgres DB.
- `L2_MAX_BLOCKS_TO_FETCH_LOGS`: Maximum blocks to fetch in one request
- `L2_MAX_GAS_FEE_ENFORCED`: Enable/disable gas fee enforcement
- `L2_MESSAGE_TREE_DEPTH`: Depth of the message Merkle tree
- `L2_EVENT_FILTER_FROM_ADDRESS`: Filter events using a from address
- `L2_EVENT_FILTER_TO_ADDRESS`: Filter events using a to address
- `L2_EVENT_FILTER_CALLDATA`: MessageSent event calldata filtering criteria expression. See [Filtrex repo](https://github.com/joewalnes/filtrex/tree/master).
<br>
You can filter by the calldata field:
<br>

Example:
`calldata.funcSignature == "0x6463fb2a" and calldata.params.messageNumber == 85804`,
- `L2_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE`: Calldata data function interface following this format: `"function transfer(address to, uint256 amount)"`. Make sure you specify parameters names in order to use syntax like `calldata.params.messageNumber`.

#### Message Processing
- `MESSAGE_SUBMISSION_TIMEOUT`: Timeout for message submission (ms)
Expand Down Expand Up @@ -80,7 +100,7 @@ All messages are stored in a configurable Postgres DB.

From the root folder, run the following command:
```bash
make fresh-start-all
make start-env-with-tracing-v2
```

Stop the postman docker container manually.
Expand Down
1 change: 1 addition & 0 deletions postman/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"class-validator": "0.14.1",
"dotenv": "16.4.5",
"ethers": "6.13.4",
"filtrex": "3.1.0",
"pg": "8.13.1",
"typeorm": "0.3.20",
"typeorm-naming-strategies": "4.1.0",
Expand Down
36 changes: 36 additions & 0 deletions postman/scripts/runPostman.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ async function main() {
...(parseInt(process.env.L1_LISTENER_BLOCK_CONFIRMATION ?? "") >= 0
? { blockConfirmation: parseInt(process.env.L1_LISTENER_BLOCK_CONFIRMATION ?? "") }
: {}),
...(process.env.L1_EVENT_FILTER_FROM_ADDRESS ||
process.env.L1_EVENT_FILTER_TO_ADDRESS ||
(process.env.L1_EVENT_FILTER_CALLDATA && process.env.L1_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE)
? {
eventFilters: {
fromAddressFilter: process.env.L1_EVENT_FILTER_FROM_ADDRESS,
toAddressFilter: process.env.L1_EVENT_FILTER_TO_ADDRESS,
...(process.env.L1_EVENT_FILTER_CALLDATA && process.env.L1_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE
? {
calldataFilter: {
criteriaExpression: process.env.L1_EVENT_FILTER_CALLDATA,
calldataFunctionInterface: process.env.L1_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE,
},
}
: {}),
},
}
: {}),
},
claiming: {
signerPrivateKey: process.env.L1_SIGNER_PRIVATE_KEY ?? "",
Expand Down Expand Up @@ -65,6 +83,24 @@ async function main() {
...(parseInt(process.env.L2_LISTENER_BLOCK_CONFIRMATION ?? "") >= 0
? { blockConfirmation: parseInt(process.env.L2_LISTENER_BLOCK_CONFIRMATION ?? "") }
: {}),
...(process.env.L2_EVENT_FILTER_FROM_ADDRESS ||
process.env.L2_EVENT_FILTER_TO_ADDRESS ||
(process.env.L2_EVENT_FILTER_CALLDATA && process.env.L2_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE)
? {
eventFilters: {
fromAddressFilter: process.env.L2_EVENT_FILTER_FROM_ADDRESS,
toAddressFilter: process.env.L2_EVENT_FILTER_TO_ADDRESS,
...(process.env.L2_EVENT_FILTER_CALLDATA && process.env.L2_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE
? {
calldataFilter: {
criteriaExpression: process.env.L2_EVENT_FILTER_CALLDATA,
calldataFunctionInterface: process.env.L2_EVENT_FILTER_CALLDATA_FUNCTION_INTERFACE,
},
}
: {}),
},
}
: {}),
},
claiming: {
signerPrivateKey: process.env.L2_SIGNER_PRIVATE_KEY ?? "",
Expand Down
2 changes: 2 additions & 0 deletions postman/src/application/postman/app/PostmanServiceClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export class PostmanServiceClient {
blockConfirmation: config.l1Config.listener.blockConfirmation,
isEOAEnabled: config.l1Config.isEOAEnabled,
isCalldataEnabled: config.l1Config.isCalldataEnabled,
eventFilters: config.l1Config.listener.eventFilters,
},
new WinstonLogger(`L1${MessageSentEventProcessor.name}`, config.loggerOptions),
);
Expand Down Expand Up @@ -245,6 +246,7 @@ export class PostmanServiceClient {
blockConfirmation: config.l2Config.listener.blockConfirmation,
isEOAEnabled: config.l2Config.isEOAEnabled,
isCalldataEnabled: config.l2Config.isCalldataEnabled,
eventFilters: config.l2Config.listener.eventFilters,
},
new WinstonLogger(`L2${MessageSentEventProcessor.name}`, config.loggerOptions),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,36 @@ describe("PostmanServiceClient", () => {
new Error("Something went wrong when trying to generate Wallet. Please check your private key."),
);
});

it("should throw an error when events filters are not valid", () => {
const postmanServiceClientOptionsWithInvalidPrivateKey: PostmanOptions = {
...postmanServiceClientOptions,
l1Options: {
...postmanServiceClientOptions.l1Options,
listener: {
...postmanServiceClientOptions.l1Options.listener,
eventFilters: {
fromAddressFilter: "0x",
},
},
claiming: {
...postmanServiceClientOptions.l1Options.claiming,
signerPrivateKey: "0x",
},
},
l2Options: {
...postmanServiceClientOptions.l2Options,
claiming: {
...postmanServiceClientOptions.l2Options.claiming,
signerPrivateKey: "0x",
},
},
};

expect(() => new PostmanServiceClient(postmanServiceClientOptionsWithInvalidPrivateKey)).toThrow(
new Error("Invalid fromAddressFilter: 0x"),
);
});
});

describe("connectDatabase", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe } from "@jest/globals";
import { getConfig } from "../utils";
import { getConfig, validateEventsFiltersConfig } from "../utils";
import {
TEST_ADDRESS_1,
TEST_ADDRESS_2,
Expand Down Expand Up @@ -235,4 +235,61 @@ describe("Config utils", () => {
});
});
});

describe("validateEventsFiltersConfig", () => {
it("should throw an error when the from address event filter is not valid", () => {
expect(() =>
validateEventsFiltersConfig({
fromAddressFilter: "0x123",
}),
).toThrow("Invalid fromAddressFilter: 0x123");
});

it("should throw an error when the to address event filter is not valid", () => {
expect(() =>
validateEventsFiltersConfig({
toAddressFilter: "0x123",
}),
).toThrow("Invalid toAddressFilter: 0x123");
});

it("should not throw an error when filters are valid", () => {
expect(() =>
validateEventsFiltersConfig({
fromAddressFilter: "0xc59d8de7f984AbC4913f0177bfb7BBdaFaC41fA6",
toAddressFilter: "0xc59d8de7f984AbC4913f0177bfb7BBdaFaC41fA6",
calldataFilter: {
criteriaExpression: `calldata.funcSignature == "0x26dfbc20" and calldata.amount > 0`,
calldataFunctionInterface: "function receiveFromOtherLayer(address recipient, uint256 amount)",
},
}),
).not.toThrow();
});

it("should throw an error when calldataFilter filter expression is invalid", () => {
expect(() =>
validateEventsFiltersConfig({
fromAddressFilter: "0xc59d8de7f984AbC4913f0177bfb7BBdaFaC41fA6",
toAddressFilter: "0xc59d8de7f984AbC4913f0177bfb7BBdaFaC41fA6",
calldataFilter: {
criteriaExpression: `calldata.funcSignature == "0x26dfbc20" and calldata.amount = 0`,
calldataFunctionInterface: "function receiveFromOtherLayer(address recipient, uint256 amount)",
},
}),
).toThrow('Invalid calldataFilter expression: calldata.funcSignature == "0x26dfbc20" and calldata.amount = 0');
});

it("should throw an error when calldataFunctionInterface is invalid", () => {
expect(() =>
validateEventsFiltersConfig({
fromAddressFilter: "0xc59d8de7f984AbC4913f0177bfb7BBdaFaC41fA6",
toAddressFilter: "0xc59d8de7f984AbC4913f0177bfb7BBdaFaC41fA6",
calldataFilter: {
criteriaExpression: `calldata.funcSignature == "0x26dfbc20" and calldata.amount > 0`,
calldataFunctionInterface: "function receiveFromOtherLayer(address recipient uint256 amount)",
},
}),
).toThrow("Invalid calldataFunctionInterface: function receiveFromOtherLayer(address recipient uint256 amount)");
});
});
});
11 changes: 10 additions & 1 deletion postman/src/application/postman/app/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ export type ListenerOptions = {
blockConfirmation?: number;
maxFetchMessagesFromDb?: number;
maxBlocksToFetchLogs?: number;
eventFilters?: {
fromAddressFilter?: string;
toAddressFilter?: string;
calldataFilter?: {
criteriaExpression: string;
calldataFunctionInterface: string;
};
};
};

export type ListenerConfig = Required<ListenerOptions>;
export type ListenerConfig = Required<Omit<ListenerOptions, "eventFilters">> &
Partial<Pick<ListenerOptions, "eventFilters">>;
Loading

0 comments on commit 12a5c33

Please sign in to comment.