From c409b9c4337f9696840894851f11d880d0e417b3 Mon Sep 17 00:00:00 2001 From: crystalin Date: Fri, 29 Nov 2024 20:45:57 +0100 Subject: [PATCH] Adds storage bisect script --- src/tools/storage-bisect.ts | 93 +++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/tools/storage-bisect.ts diff --git a/src/tools/storage-bisect.ts b/src/tools/storage-bisect.ts new file mode 100644 index 0000000..159cbd4 --- /dev/null +++ b/src/tools/storage-bisect.ts @@ -0,0 +1,93 @@ +import yargs from "yargs"; +import { ApiPromise } from '@polkadot/api'; +import { getApiFor, NETWORK_YARGS_OPTIONS } from "../utils/networks.ts"; + + +const argv = yargs(process.argv.slice(2)) + .usage("Usage: $0") + .version("1.0.0") + .options({ + ...NETWORK_YARGS_OPTIONS, + start: { + type: "number", + description: "Block number to start", + default: 0 + }, + end: { + type: "number", + description: "Block number to end", + default: 10000000 + }, + key: { + type: "string", + description: "Storage key to look for", + required: true + }, + }).argv; + +async function dichotomicSearch( + api: ApiPromise, + startBlock: number, + endBlock: number, + storageKey: string, +): Promise { + let left = startBlock; + let right = endBlock; + + // Get the value of the storage key at a specific block + async function getStorageValueAtBlock(blockNumber: number): Promise { + const blockHash = await api.rpc.chain.getBlockHash(blockNumber); + const storageValue = (await api.rpc.state.getStorage(storageKey, blockHash.toString())) as any; + console.log(`[${blockNumber}: ${blockHash.toString()}] value: ${storageValue.toHex()} `); + return storageValue.toHex(); + } + + const initialValue = await getStorageValueAtBlock(startBlock); + console.log(`Initial value: ${initialValue}`); + console.log(`Starting dichotomic search from block ${startBlock} to ${endBlock}`); + + // Perform binary search + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const midValue = await getStorageValueAtBlock(mid); + + if (midValue !== initialValue) { + // If the value changed, narrow the search range to the left + right = mid - 1; + } else { + // If the value is the same, narrow the search range to the right + left = mid + 1; + } + } + + // Check if the change was found + if (left <= endBlock) { + return left; + } + + return null; // No change found within the range +} + +async function main() { + const api = await getApiFor(argv); + + const startBlock = argv.start; + const endBlock = Math.min(argv.end, (await api.rpc.chain.getHeader()).number.toNumber()); + const storageKey = argv.key + + console.log("===============================================") + console.log("Warning, this will only work if a single change of value happened during the range") + console.log("===============================================") + + const result = await dichotomicSearch(api, startBlock, endBlock, storageKey); + + if (result !== null) { + console.log(`Change detected at block: ${result}`); + } else { + console.log('No change detected in the specified range.'); + } + + await api.disconnect(); +} + +main().catch(console.error);