UNPKG

@bsv/overlay

Version:
172 lines (141 loc) 5.78 kB
import { GraphNode, OverlayGASPStorage } from '../GASP/OverlayGASPStorage' import { Transaction, MerklePath } from '@bsv/sdk' import { GASPNode } from '@bsv/gasp' describe('OverlayGASPStorage', () => { let overlayStorage: OverlayGASPStorage let mockEngine: any beforeEach(() => { mockEngine = { storage: { findOutput: jest.fn(() => undefined), findUTXOsForTopic: jest.fn() }, managers: {} } overlayStorage = new OverlayGASPStorage('test-topic', mockEngine) }) describe('appendToGraph', () => { it('should append a new node to an empty graph', async () => { const mockTx = { rawTx: '001122', outputIndex: 0, graphID: 'txid123.0' } // Use actual Transaction implementation const parsedTx = Transaction.fromHex(mockTx.rawTx) await overlayStorage.appendToGraph(mockTx) expect(Object.keys(overlayStorage.temporaryGraphNodeRefs).length).toBe(1) expect(overlayStorage.temporaryGraphNodeRefs['txid123.0'].txid).toBe(parsedTx.id('hex')) }) it('throws error when max nodes are exceeded', async () => { overlayStorage.maxNodesInGraph = 1 const graphNode: GraphNode = { txid: 'txid123', children: [], rawTx: '', graphID: 'txid4321.2', outputIndex: 0 } overlayStorage.temporaryGraphNodeRefs['txid123.0'] = graphNode const mockTx = { rawTx: '334455', outputIndex: 1, graphID: 'txid234.1' } await expect(overlayStorage.appendToGraph(mockTx)).rejects.toThrow('The max number of nodes in transaction graph has been reached!') }) }) describe('findKnownUTXOs', () => { it('should return known UTXOs since a given timestamp', async () => { const mockUTXOs = [{ txid: 'txid1', outputIndex: 0, score: 0 }, { txid: 'txid2', outputIndex: 1, score: 0 }] mockEngine.storage.findUTXOsForTopic.mockResolvedValue(mockUTXOs) const result = await overlayStorage.findKnownUTXOs(1234567890) expect(result).toEqual([ { txid: 'txid1', outputIndex: 0, score: 0 }, { txid: 'txid2', outputIndex: 1, score: 0 } ]) expect(mockEngine.storage.findUTXOsForTopic).toHaveBeenCalledWith('test-topic', 1234567890) }) it('should handle errors correctly', async () => { mockEngine.storage.findUTXOsForTopic.mockRejectedValue(new Error('Database error')) await expect(overlayStorage.findKnownUTXOs(1234567890)).rejects.toThrow('Database error') }) }) describe('hydrateGASPNode', () => { it('should throw an error if no output is found', async () => { await expect(overlayStorage.hydrateGASPNode('graphID', 'txid', 0, false)).rejects.toThrow('No matching output found!') }) // TODO: Further test coverage }) describe('findNeededInputs', () => { // TODO: Write more complicated test cases it('should return inputs needed for further verification when no proof is present', async () => { const mockTx: GASPNode = { rawTx: '001122', proof: undefined, graphID: 'txid123.0', outputIndex: 0 } const parsedTx = { inputs: [{ sourceTXID: 'inputTxid1', sourceOutputIndex: 0 }], toBEEF: jest.fn(), id: jest.fn().mockReturnValue('txid123') } Transaction.fromHex = jest.fn().mockReturnValue(parsedTx) const result = await overlayStorage.findNeededInputs(mockTx) expect(result).toEqual({ requestedInputs: { 'inputTxid1.0': { metadata: false } } }) }) it('should return inputs needed for further verification when proof is present', async () => { const mockTx: GASPNode = { rawTx: '001122', proof: 'someproof', graphID: 'txid123.0', outputIndex: 0 } const parsedTx = { inputs: [{ sourceTXID: 'neededTxid', sourceOutputIndex: 1 }], toBEEF: jest.fn(), id: jest.fn().mockReturnValue('txid123'), merklePath: {} } Transaction.fromHex = jest.fn().mockReturnValue(parsedTx) MerklePath.fromHex = jest.fn().mockReturnValue(parsedTx.merklePath) mockEngine.managers['test-topic'] = { identifyAdmissibleOutputs: jest.fn().mockResolvedValue({ outputsToAdmit: [] }), identifyNeededInputs: jest.fn().mockResolvedValue([{ txid: 'neededTxid', outputIndex: 1 }]) } const result = await overlayStorage.findNeededInputs(mockTx) expect(result).toEqual({ requestedInputs: { 'neededTxid.1': { metadata: false } } }) }) }) describe('discardGraph', () => { it('should discard the graph and its nodes', async () => { const graphNode1: GraphNode = { txid: 'txid123', graphID: 'txid123.0', rawTx: 'rawTxData', outputIndex: 0, children: [], parent: undefined } overlayStorage.temporaryGraphNodeRefs['txid123.0'] = graphNode1 const parentNode: GraphNode = { txid: 'txid123', graphID: 'txid123.0', rawTx: 'rawTxData', outputIndex: 0, children: [] } const graphNode2: GraphNode = { txid: 'txid124', graphID: 'txid123.0', rawTx: 'rawTxData', outputIndex: 1, children: [], parent: parentNode } overlayStorage.temporaryGraphNodeRefs['txid124.0'] = graphNode2 await overlayStorage.discardGraph('txid123.0') expect(overlayStorage.temporaryGraphNodeRefs['txid123.0']).toBeUndefined() expect(overlayStorage.temporaryGraphNodeRefs['txid124.0']).toBeUndefined() }) }) it('should handle non-existent graphID', async () => { await overlayStorage.discardGraph('nonexistent.0') expect(Object.keys(overlayStorage.temporaryGraphNodeRefs).length).toBe(0) }) })