Skip to content
Merged
13 changes: 11 additions & 2 deletions packages/btcindexer/src/btcindexer.helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import type { WorkerEntrypoint } from "cloudflare:workers";
import { BtcNet, type BlockQueueRecord } from "@gonative-cc/lib/nbtc";
import { toSuiNet, type SuiNet } from "@gonative-cc/lib/nsui";
import { D1Storage } from "@gonative-cc/sui-indexer/storage";
import type { SuiIndexerRpc } from "@gonative-cc/sui-indexer/rpc-interface";
import {
type SuiIndexerRpc,
RedeemRequestStatus,
type FinalizeRedeemItem,
} from "@gonative-cc/sui-indexer/rpc-interface";
import { dropTables, initDb } from "@gonative-cc/lib/test-helpers/init_db";

import { Indexer } from "./btcindexer";
Expand Down Expand Up @@ -179,8 +183,13 @@ export async function setupTestIndexerSuite(
indexerStorage.getBroadcastedBtcRedeemTxIds(network),
confirmRedeem: (txIds: string[], blockHeight: number, blockHash: string) =>
indexerStorage.confirmRedeem(txIds, blockHeight, blockHash),
finalizeRedeem: () => Promise.resolve(),
finalizeRedeems: async (requests: FinalizeRedeemItem[]) => {
await Promise.all(requests.map((r) => indexerStorage.setRedeemFinalized(r.redeemId)));
},
putRedeemTx: () => Promise.resolve(),
getConfirmingRedeems: (network: string) => indexerStorage.getConfirmingRedeems(network),
updateRedeemStatus: (redeemId: number, status: RedeemRequestStatus) =>
indexerStorage.updateRedeemStatus(redeemId, status),
} as unknown as Service<SuiIndexerRpc & WorkerEntrypoint>;

const indexer = new Indexer(
Expand Down
137 changes: 43 additions & 94 deletions packages/btcindexer/src/btcindexer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,76 +202,77 @@ describe("Indexer.constructMerkleProof", () => {
});
});

describe("Indexer.handleReorgs", () => {
it("should do nothing if no reorg", async () => {
describe("Indexer.splitActiveInactiveTxs", () => {
it("should return active ID when address is active", () => {
const pendingTx = {
tx_id: "tx1",
block_hash: "hash_A",
block_height: 100,
btc_network: BtcNet.REGTEST,
deposit_address: REGTEST_DATA[329]!.depositAddr,
};
await suite.db
.prepare(
"INSERT INTO btc_blocks (height, hash, network, processed_at, is_scanned) VALUES (?, ?, ?, ?, ?)",
)
.bind(100, "hash_A", "regtest", Date.now(), 1)
.run();

const { reorgedTxIds } = await indexer.handleReorgs([pendingTx]);
expect(reorgedTxIds.length).toEqual(0);
});

it("should generate a reset statement if reorg detected", async () => {
const pendingTx = {
tx_id: "tx1",
block_hash: "hash_A",
block_hash: null,
block_height: 100,
btc_network: BtcNet.REGTEST,
deposit_address: REGTEST_DATA[329]!.depositAddr,
};
await suite.db
.prepare(
"INSERT INTO btc_blocks (height, hash, network, processed_at, is_scanned) VALUES (?, ?, ?, ?, ?)",
)
.bind(100, "hash_A_reorged", "regtest", Date.now(), 1)
.run();
const { reorgedTxIds } = await indexer.handleReorgs([pendingTx]);
expect(reorgedTxIds.length).toEqual(1);
const { activeTxIds } = indexer.splitActiveInactiveTxs([pendingTx]);
expect(activeTxIds.length).toEqual(1);
expect(activeTxIds[0]).toEqual("tx1");
});
});

describe("Indexer.findFinalizedTxs", () => {
it("should generate a finalize statement when enough confirmations", () => {
describe("Indexer.splitActiveInactiveTxs (Inactive)", () => {
it("should return inactiveId if address is not active", () => {
const pkg = indexer.getPackageConfig(1);
if (pkg) pkg.is_active = false;

const pendingTx = {
tx_id: "tx1",
block_hash: null,
block_height: 100,
btc_network: BtcNet.REGTEST,
deposit_address: REGTEST_DATA[329]!.depositAddr,
};
const latestHeight = 107;
const { activeTxIds } = indexer.selectFinalizedNbtcTxs([pendingTx], latestHeight);
expect(activeTxIds.length).toEqual(1);
const result = indexer.splitActiveInactiveTxs([pendingTx]);

expect(result.activeTxIds.length).toEqual(0);
expect(result.inactiveTxIds.length).toEqual(1);

// Restore active state for other tests
if (pkg) pkg.is_active = true;
});

it("should do nothing when not enough confirmations", () => {
it("should return inactiveId if address is inactive but package is active", () => {
const pendingTx = {
tx_id: "tx1",
block_hash: null,
block_height: 100,
btc_network: BtcNet.REGTEST,
deposit_address: REGTEST_DATA[329]!.depositAddr,
deposit_address: "inactive_address",
};
const latestHeight = 106;
const { activeTxIds } = indexer.selectFinalizedNbtcTxs([pendingTx], latestHeight);
expect(activeTxIds.length).toEqual(0);

const originalMap = indexer.nbtcDepositAddrMap;
indexer.nbtcDepositAddrMap = new Map([
[
"inactive_address",
{
setup_id: 1,
is_active: false,
},
],
]);

const result = indexer.splitActiveInactiveTxs([pendingTx]);

expect(result.activeTxIds.length).toEqual(0);
expect(result.inactiveTxIds.length).toEqual(1);

indexer.nbtcDepositAddrMap = originalMap;
});
});

describe.skip("Indexer.updateConfirmationsAndFinalize", () => {
it("should be tested later", () => {
// TODO: add a test for the scanNewBlocks using the same data
it("should finalize transactions with enough confirmations", async () => {
const indexer = await indexerFromEnv(env);
// ... setup ...
await indexer.updateConfirmationsAndFinalize();
// ... assertions ...
});
});

Expand Down Expand Up @@ -595,58 +596,6 @@ describe("Indexer.processBlock", () => {
});
});

describe("Indexer.findFinalizedTxs (Inactive)", () => {
it("should return inactiveId if address is not active", () => {
const pkg = indexer.getPackageConfig(1);
if (pkg) pkg.is_active = false;

const pendingTx = {
tx_id: "tx1",
block_hash: null,
block_height: 100,
btc_network: BtcNet.REGTEST,
deposit_address: REGTEST_DATA[329]!.depositAddr,
};
const latestHeight = 107;
const result = indexer.selectFinalizedNbtcTxs([pendingTx], latestHeight);

expect(result.activeTxIds.length).toEqual(0);
expect(result.inactiveTxIds.length).toEqual(1);

// Restore active state for other tests
if (pkg) pkg.is_active = true;
});

it("should return inactiveId if address is inactive but package is active", () => {
const pendingTx = {
tx_id: "tx1",
block_hash: null,
block_height: 100,
btc_network: BtcNet.REGTEST,
deposit_address: "inactive_address",
};

const originalMap = indexer.nbtcDepositAddrMap;
indexer.nbtcDepositAddrMap = new Map([
[
"inactive_address",
{
setup_id: 1,
is_active: false,
},
],
]);

const latestHeight = 107;
const result = indexer.selectFinalizedNbtcTxs([pendingTx], latestHeight);

expect(result.activeTxIds.length).toEqual(0);
expect(result.inactiveTxIds.length).toEqual(1);

indexer.nbtcDepositAddrMap = originalMap;
});
});

describe("CFStorage.insertBlockInfo (Stale Block Protection)", () => {
it("should return TRUE and insert data when block is new", async () => {
const record: BlockQueueRecord = {
Expand Down
Loading
Loading