Skip to content

Commit

Permalink
adding efficient-ish sliding window
Browse files Browse the repository at this point in the history
  • Loading branch information
sklppy88 committed Nov 22, 2024
1 parent 131723d commit 1677959
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 14 deletions.
42 changes: 31 additions & 11 deletions yarn-project/pxe/src/simulator_oracle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,30 +347,50 @@ export class SimulatorOracle implements DBOracle {
sender: AztecAddress,
recipient: AztecAddress,
): Promise<void> {
const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
const appTaggingSecret = await this.#calculateTaggingSecret(contractAddress, sender, recipient);
let [currentIndex] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);

const WINDOW = 5;
const INDEX_OFFSET = 10;

let previousEmptyBack = 0;
let currentEmptyBack = 0;
let currentEmptyFront: number;

let possibleLogs: TxScopedL2Log[][];
// The below code is trying to find the index of the start of the first window in which for all elements of window, we do not see logs.
// We take our window size, and fetch the node for these logs. We store both the amount of empty consecutive slots from the front and the back.
// We use our current empty consecutive slots from the front, as well as the previous consecutive empty slots from the back to see if we ever hit a time where there
// is a window in which we see the combination of them to be greater than the window's size. If true, we rewind current index to the start of said window and use it.
// Assuming two windows of 5:
// [0, 1, 0, 0, 0], [0, 0, 0, 1, 1]
// We can see that when processing the second window, the previous amount of empty slots from the back of the window (3), added with the empty elements from the front of the window (3)
// is greater than 5 (6) and therefore we have found a window to use.
// We simply need to take the number of elements (10) - the size of the window (5) - the number of consecutive empty elements from the back of the last window (3) = 2;
// This is the first index of our desired window.

do {
const currentTags = [...new Array(WINDOW)].map((_, i) => {
const currentTags = [...new Array(INDEX_OFFSET)].map((_, i) => {
const indexedAppTaggingSecret = new IndexedTaggingSecret(appTaggingSecret, currentIndex + i);
return indexedAppTaggingSecret.computeTag(recipient);
});
previousEmptyBack = currentEmptyBack;

const possibleLogs = await this.aztecNode.getLogsByTags(currentTags);

const indexOfFirstLog = possibleLogs.findIndex(possibleLog => possibleLog.length !== 0);
currentEmptyFront = indexOfFirstLog === -1 ? INDEX_OFFSET : indexOfFirstLog;

possibleLogs = await this.aztecNode.getLogsByTags(currentTags);
currentIndex += WINDOW;
} while (possibleLogs.every(log => log.length !== 0));
const indexOfLastLog = possibleLogs.findLastIndex(possibleLog => possibleLog.length !== 0);
currentEmptyBack = indexOfLastLog === -1 ? INDEX_OFFSET : (INDEX_OFFSET - 1 - indexOfLastLog);

// We are getting the first empty index, and subtracting it from our WINDOW. So if our first empty index is 1,
// and our current index is 5, which means that we went through the loop one time, we take our current index,
// and subtract WINDOW - first empty index (= 5-1) from it. This means that new index will be 1.
const newIndex = currentIndex - (WINDOW - possibleLogs.findIndex(log => log.length === 0));
currentIndex += INDEX_OFFSET;
} while (currentEmptyFront + previousEmptyBack < INDEX_OFFSET);

// We unwind the entire current window and the amount of consecutive empty slots from the previous window
const newIndex = currentIndex - (INDEX_OFFSET + previousEmptyBack)

await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(appTaggingSecret, newIndex)]);

const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
this.log.debug(
`Syncing logs for sender ${sender}, secret ${appTaggingSecret}:${currentIndex} at contract: ${contractName}(${contractAddress})`,
);
Expand Down
24 changes: 21 additions & 3 deletions yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ describe('Simulator oracle', () => {
await keyStore.addAccount(sender.secretKey, sender.completeAddress.partialAddress);
}

const senderOffset = 0;
let senderOffset = 0;
generateMockLogs(senderOffset);

// Recompute the secrets (as recipient) to ensure indexes are updated
Expand All @@ -296,10 +296,28 @@ describe('Simulator oracle', () => {
);
}

const indexesAsSenderAfterSync = await database.getTaggingSecretsIndexesAsSender(secrets);
let indexesAsSenderAfterSync = await database.getTaggingSecretsIndexesAsSender(secrets);
expect(indexesAsSenderAfterSync).toStrictEqual([1, 1, 1, 1, 1, 2, 2, 2, 2, 2]);

expect(aztecNode.getLogsByTags.mock.calls.length).toBe(NUM_SENDERS);
// Two windows are fetch for each sender
expect(aztecNode.getLogsByTags.mock.calls.length).toBe(NUM_SENDERS * 2);
aztecNode.getLogsByTags.mockReset();

// We add more logs at the end of the window to make sure we only detect them and bump the indexes if it lies within our window
senderOffset = 11;
generateMockLogs(senderOffset);
for (let i = 0; i < senders.length; i++) {
await simulatorOracle.syncTaggedLogsAsSender(
contractAddress,
senders[i].completeAddress.address,
recipient.address,
);
}

indexesAsSenderAfterSync = await database.getTaggingSecretsIndexesAsSender(secrets);
expect(indexesAsSenderAfterSync).toStrictEqual([1, 1, 1, 1, 1, 13, 13, 13, 13, 13]);

expect(aztecNode.getLogsByTags.mock.calls.length).toBe(NUM_SENDERS * 2);
});

it('should sync tagged logs with a sender index offset', async () => {
Expand Down

0 comments on commit 1677959

Please sign in to comment.