Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: parallelise intra-block processing #137

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

mfw78
Copy link
Contributor

@mfw78 mfw78 commented Jan 19, 2024

Description

In order to increase performance of the watch-tower, multiple conditional orders can be polled simultaneously in order to reduce per-block processing times.

Changes

  • Parallelises intra-block processing
  • Metrics to processing time per block, processing time per owner, and post-processing

How to test

  1. Adjust the configuration and run against a current chain (ie. mainnet, xdai, or goerli)
  2. After sync, dump the database from the /api/dump/<chainId> endpoint
  3. Compare dump from (3) with a dump from the pre-parallelised version

Related Issues

Fixes #128

@mfw78 mfw78 added the enhancement New feature or request label Jan 19, 2024
@mfw78 mfw78 requested review from anxolin and a team January 19, 2024 11:57
@mfw78 mfw78 self-assigned this Jan 19, 2024
Copy link
Contributor

@anxolin anxolin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, i found the code a bit hard to read. It was already too complex, but now its growing and growing in complexity.

This asks for a refactor and cleanup, especially if we are increasing the parallelism.


export const pollingByOwnerDurationSeconds = new client.Histogram({
name: "watch_tower_polling_by_owner_duration_seconds",
help: "Duration of polling run",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same tests as the one above

const log = getLogger(
"checkForAndPlaceOrder:checkForAndPlaceOrder",
chainId.toString(),
blockNumber.toString(),
ownerRef
(ownerCounter++).toString()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it won't give us the same order between blocks now (unless we use value from the map argument)

you can use the index of map, and rename the var to ownerCounter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map


return {
order,
_delete: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not pretty. Do you see a chance of breaking down the logic a bit:

const orderPromises = Array.from(conditionalOrders.values()).map(breakItIntoFunctions)

This way you can also define better types for what these functions should return.

This type looks not too nice:

image

Also, could you give a name like the others props for _delete. Think what you model here, in this case is that we should not keep polling this order for future blocks, then you can pick a name that reflects that.

doNotCheckAgain, dropOrderForever, getTheFu**OutOfHere

continue;
}
// Get all the results and filter out the undefined ones
const results = (await Promise.all(orderPromises)).filter((r) => !!r);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid names like r

"Skipping conditional order. Reason: AcceptPolicy: SKIP"
);

return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might not be obvious why you return undefined

You could model it in the data this return, or if you really want to return undefined, to make it more readable you can do:

type SkipOrder = undefined;
const SKIP_ORDER: SkipOrder = undefined;

case FilterAction.SKIP:
   log.debug(
        "Skipping conditional order. Reason: AcceptPolicy: SKIP"
    );
   return SKIP_ORDER;

// Process all the orders
for (const result of results) {
if (!result) {
throw new Error("Unexpected error: orderResult is undefined");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would this happen?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you filtered before, afait you just have a type issue.
what you might be looking for is https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards

const id = ConditionalOrderSDK.leafToId(order.params);

// Search for the order in the registry and update / delete it
for (const o of Array.from(conditionalOrders.values())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we not use names like o

const id = ConditionalOrderSDK.leafToId(order.params);

// Search for the order in the registry and update / delete it
for (const o of Array.from(conditionalOrders.values())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you made this Array.from(conditionalOrders.values()) a few times in the code

if (conditionalOrders === undefined && results.length > 0) {
throw new Error(
"Unexpected error: conditionalOrders is undefined but results is not empty"
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as for line 295


// Search for the order in the registry and update / delete it
for (const o of Array.from(conditionalOrders.values())) {
if (ConditionalOrderSDK.leafToId(o.params) === id) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arent you calculating the leafToId for all conditionalOrders.values() orders for each result you have?
it looks like you repeat the work over and over.

Isn't it better to build a Map "ID --> Order"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

chore: parallelise intra-block processing
2 participants