-
Notifications
You must be signed in to change notification settings - Fork 481
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Admin reset key event may have reset the key sometimes (#1610)
- Loading branch information
1 parent
56f8ab1
commit c78f01b
Showing
6 changed files
with
166 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@farcaster/hubble": patch | ||
--- | ||
|
||
fix: Admin reset key event may have reset the key sometimes |
61 changes: 61 additions & 0 deletions
61
apps/hubble/src/storage/db/migrations/7.clearAdminResets.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { performDbMigrations } from "./migrations.js"; | ||
import { jestRocksDB } from "../jestUtils.js"; | ||
import { MerkleTrie } from "../../../network/sync/merkleTrie.js"; | ||
import { SyncId } from "../../../network/sync/syncId.js"; | ||
import { Factories, HubError, OnChainEvent, SignerEventType } from "@farcaster/hub-nodejs"; | ||
import StoreEventHandler from "../../stores/storeEventHandler.js"; | ||
import OnChainEventStore from "../../stores/onChainEventStore.js"; | ||
import { getOnChainEvent } from "../onChainEvent.js"; | ||
import { ResultAsync } from "neverthrow"; | ||
|
||
const db = jestRocksDB("clearAdminResets.migration.test"); | ||
|
||
describe("clearAdminResets migration", () => { | ||
const addEvent = async function (event: OnChainEvent, store: OnChainEventStore, trie: MerkleTrie) { | ||
await expect(store.mergeOnChainEvent(event)).resolves.toBeTruthy(); | ||
const syncId = SyncId.fromOnChainEvent(event); | ||
await trie.insert(syncId); | ||
await trie.commitToDb(); | ||
await expectExists(event, trie, true); | ||
}; | ||
|
||
const expectExists = async function (event: OnChainEvent, trie: MerkleTrie, shouldExist: boolean) { | ||
const dbResult = await ResultAsync.fromPromise( | ||
getOnChainEvent(db, event.type, event.fid, event.blockNumber, event.logIndex), | ||
(e) => e as HubError, | ||
); | ||
expect(dbResult.isOk()).toBe(shouldExist); | ||
const syncId = SyncId.fromOnChainEvent(event); | ||
expect(await trie.exists(syncId)).toBe(shouldExist); | ||
}; | ||
|
||
test("should delete admin reset signer events", async () => { | ||
const syncTrie = new MerkleTrie(db); | ||
const store = new OnChainEventStore(db, new StoreEventHandler(db)); | ||
|
||
const idRegistryEvent = Factories.IdRegistryOnChainEvent.build(); | ||
const keyRegistryEvent = Factories.SignerOnChainEvent.build(); | ||
const keyRegistryResetEvent = Factories.SignerOnChainEvent.build({ | ||
signerEventBody: Factories.SignerEventBody.build({ eventType: SignerEventType.ADMIN_RESET }), | ||
}); | ||
const storageRegistryEvent = Factories.StorageRentOnChainEvent.build(); | ||
|
||
await addEvent(idRegistryEvent, store, syncTrie); | ||
await addEvent(keyRegistryEvent, store, syncTrie); | ||
await addEvent(keyRegistryResetEvent, store, syncTrie); | ||
await addEvent(storageRegistryEvent, store, syncTrie); | ||
|
||
const success = await performDbMigrations(db, 6, 7); | ||
expect(success).toBe(true); | ||
|
||
const uncachedSyncTrie = new MerkleTrie(db); | ||
await uncachedSyncTrie.initialize(); | ||
|
||
// Admin reset is removed | ||
await expectExists(keyRegistryResetEvent, uncachedSyncTrie, false); | ||
// Rest are unaffected | ||
await expectExists(idRegistryEvent, uncachedSyncTrie, true); | ||
await expectExists(keyRegistryEvent, uncachedSyncTrie, true); | ||
await expectExists(storageRegistryEvent, uncachedSyncTrie, true); | ||
}); | ||
}); |
54 changes: 54 additions & 0 deletions
54
apps/hubble/src/storage/db/migrations/7.clearAdminResets.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/** | ||
Remove admin resets so they can be re-added correctly (old logic picked first signer and did not check for the exact key) | ||
*/ | ||
|
||
import { logger } from "../../../utils/logger.js"; | ||
import RocksDB from "../rocksdb.js"; | ||
import { OnChainEventPostfix, RootPrefix } from "../types.js"; | ||
import { Result } from "neverthrow"; | ||
import { HubError, isSignerOnChainEvent, OnChainEvent, SignerEventType } from "@farcaster/hub-nodejs"; | ||
import { SyncId } from "../../../network/sync/syncId.js"; | ||
import { MerkleTrie } from "../../../network/sync/merkleTrie.js"; | ||
|
||
const log = logger.child({ component: "clearAdminResets" }); | ||
|
||
export const clearAdminResets = async (db: RocksDB): Promise<boolean> => { | ||
log.info({}, "Starting clearAdminResets migration"); | ||
const start = Date.now(); | ||
|
||
const syncTrie = new MerkleTrie(db); | ||
await syncTrie.initialize(); | ||
let count = 0; | ||
|
||
await db.forEachIteratorByPrefix( | ||
Buffer.from([RootPrefix.OnChainEvent, OnChainEventPostfix.OnChainEvents]), | ||
async (key, value) => { | ||
if (!key || !value) { | ||
return; | ||
} | ||
|
||
const result = Result.fromThrowable( | ||
() => OnChainEvent.decode(new Uint8Array(value as Buffer)), | ||
(e) => e as HubError, | ||
)(); | ||
if (result.isOk()) { | ||
const event = result.value; | ||
if (isSignerOnChainEvent(event) && event.signerEventBody.eventType === SignerEventType.ADMIN_RESET) { | ||
count += 1; | ||
try { | ||
await db.del(key); | ||
await syncTrie.deleteBySyncId(SyncId.fromOnChainEvent(event)); | ||
} catch (e) { | ||
log.error({ err: e }, `Failed to delete event ${event.type} ${event.fid} from block ${event.blockNumber}`); | ||
} | ||
} | ||
} | ||
}, | ||
{}, | ||
1 * 60 * 60 * 1000, | ||
); | ||
await syncTrie.commitToDb(); | ||
await syncTrie.stop(); | ||
log.info({ duration: Date.now() - start }, `Finished clearAdminResets migration. Removed ${count} events`); | ||
return true; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters