Skip to content

Commit

Permalink
Simplified block indexing walk to always use getblockhash
Browse files Browse the repository at this point in the history
  • Loading branch information
summraznboi committed Apr 17, 2024
1 parent 09d4938 commit 4abdaf6
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 133 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@magiceden-oss/runestone-lib",
"version": "0.8.2-alpha",
"version": "0.9.0-alpha",
"description": "",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
135 changes: 6 additions & 129 deletions src/indexer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,35 +72,29 @@ export class RunestoneIndexer {
return;
}

this._updateInProgress = this._rpc.getblockhashbyheight
? this.updateRuneUtxoBalancesWithBlockHeightImpl(
this._rpc.getblockhashbyheight.bind(this._rpc)
)
: this.updateRuneUtxoBalancesImpl();
this._updateInProgress = this.updateRuneUtxoBalancesImpl();
try {
await this._updateInProgress;
} finally {
this._updateInProgress = null;
}
}

private async updateRuneUtxoBalancesWithBlockHeightImpl(
getblockhashbyheight: (blockheight: number) => Promise<string | null>
) {
private async updateRuneUtxoBalancesImpl() {
const currentStorageBlock = await this._storage.getCurrentBlock();
if (currentStorageBlock) {
// walk down until matching hash is found
const reorgBlockhashesToIndex: string[] = [];
let blockheight = currentStorageBlock.height;
let blockhash = await getblockhashbyheight(blockheight);
let blockhash = (await this._rpc.getblockhash({ height: blockheight })).result;
let storageBlockHash: string | null = currentStorageBlock.hash;
while (storageBlockHash !== blockhash) {
if (blockhash) {
reorgBlockhashesToIndex.push(blockhash);
}

blockheight--;
blockhash = await getblockhashbyheight(blockheight);
blockhash = (await this._rpc.getblockhash({ height: blockheight })).result;
storageBlockHash = await this._storage.getBlockhash(blockheight);
}

Expand All @@ -127,7 +121,7 @@ export class RunestoneIndexer {
Network.getFirstRuneHeight(this._network),
currentStorageBlock ? currentStorageBlock.height + 1 : 0
);
let blockhash = await getblockhashbyheight(blockheight);
let blockhash = (await this._rpc.getblockhash({ height: blockheight })).result;
while (blockhash !== null) {
const blockResult = await this._rpc.getblock({ blockhash, verbosity: 2 });
if (blockResult.error !== null) {
Expand All @@ -144,124 +138,7 @@ export class RunestoneIndexer {
await this._storage.saveBlockIndex(runeUpdater);

blockheight++;
blockhash = await getblockhashbyheight(blockheight);
}
}

private async updateRuneUtxoBalancesImpl() {
const newBlockhashesToIndex: string[] = [];

const currentStorageBlock = await this._storage.getCurrentBlock();
if (currentStorageBlock !== null) {
// If rpc block indexing is ahead of our storage, let's save up all block hashes
// until we arrive back to the current storage's block tip.
const bestblockhashResult = await this._rpc.getbestblockhash();
if (bestblockhashResult.error !== null) {
throw bestblockhashResult.error;
}
const bestblockhash = bestblockhashResult.result;

let rpcBlockResult = await this._rpc.getblock({
blockhash: bestblockhash,
verbosity: 1,
});
if (rpcBlockResult.error !== null) {
throw rpcBlockResult.error;
}
let rpcBlock = rpcBlockResult.result;

while (rpcBlock.height > currentStorageBlock.height) {
newBlockhashesToIndex.push(rpcBlock.hash);

rpcBlockResult = await this._rpc.getblock({
blockhash: rpcBlock.previousblockhash,
verbosity: 1,
});
if (rpcBlockResult.error !== null) {
throw rpcBlockResult.error;
}
rpcBlock = rpcBlockResult.result;
}

// Handle edge case where storage block height is higher than rpc node block
// (such as pointing to a newly indexing rpc node)
let storageBlockhash =
currentStorageBlock && currentStorageBlock.height === rpcBlock.height
? currentStorageBlock.hash
: await this._storage.getBlockhash(rpcBlock.height);

// Now rpc and storage blocks are at the same height,
// iterate until they are also the same hash
while (rpcBlock.hash !== storageBlockhash) {
newBlockhashesToIndex.push(rpcBlock.hash);

rpcBlockResult = await this._rpc.getblock({
blockhash: rpcBlock.previousblockhash,
verbosity: 1,
});
if (rpcBlockResult.error !== null) {
throw rpcBlockResult.error;
}
rpcBlock = rpcBlockResult.result;

storageBlockhash = await this._storage.getBlockhash(rpcBlock.height);
}

// We can reset our storage state to where rpc node and storage matches
if (currentStorageBlock && currentStorageBlock.hash !== rpcBlock.hash) {
await this._storage.resetCurrentBlock(rpcBlock);
}
} else {
const firstRuneHeight = Network.getFirstRuneHeight(this._network);

// Iterate through the rpc blocks until we reach first rune height
const bestblockhashResult = await this._rpc.getbestblockhash();
if (bestblockhashResult.error !== null) {
throw bestblockhashResult.error;
}
const bestblockhash = bestblockhashResult.result;

let rpcBlockResult = await this._rpc.getblock({
blockhash: bestblockhash,
verbosity: 1,
});
if (rpcBlockResult.error !== null) {
throw rpcBlockResult.error;
}
let rpcBlock = rpcBlockResult.result;

while (rpcBlock.height >= firstRuneHeight) {
newBlockhashesToIndex.push(rpcBlock.hash);

rpcBlockResult = await this._rpc.getblock({
blockhash: rpcBlock.previousblockhash,
verbosity: 1,
});
if (rpcBlockResult.error !== null) {
throw rpcBlockResult.error;
}
rpcBlock = rpcBlockResult.result;
}
}

// Finally start processing balances using newBlockhashesToIndex
let blockhash = newBlockhashesToIndex.pop();
while (blockhash !== undefined) {
const blockResult = await this._rpc.getblock({ blockhash, verbosity: 2 });
if (blockResult.error !== null) {
throw blockResult.error;
}
const block = blockResult.result;
const reorg = currentStorageBlock ? currentStorageBlock.height >= block.height : false;

const runeUpdater = new RuneUpdater(this._network, block, reorg, this._storage, this._rpc);

for (const [txIndex, tx] of block.tx.entries()) {
await runeUpdater.indexRunes(tx, txIndex);
}

await this._storage.saveBlockIndex(runeUpdater);
blockhash = newBlockhashesToIndex.pop();
blockhash = (await this._rpc.getblockhash({ height: blockheight })).result;
}
}
}
8 changes: 5 additions & 3 deletions src/rpcclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ export type GetBlockParams = {
verbosity?: 0 | 1 | 2;
};

export type GetBlockhashParams = {
height: number;
};

export type GetRawTransactionParams = {
txid: string;
verbose?: boolean;
Expand Down Expand Up @@ -93,7 +97,7 @@ export type RpcResponse<T> =
};

export interface BitcoinRpcClient {
getbestblockhash(): Promise<RpcResponse<string>>;
getblockhash({ height }: GetBlockhashParams): Promise<RpcResponse<string>>;
getblock<T extends GetBlockParams>({
verbosity,
blockhash,
Expand All @@ -103,6 +107,4 @@ export interface BitcoinRpcClient {
verbose,
blockhash,
}: T): Promise<RpcResponse<GetRawTransactionReturn<T>>>;

getblockhashbyheight?(blockheight: number): Promise<string | null>;
}

0 comments on commit 4abdaf6

Please sign in to comment.