{"mappings":"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","sources":["source/index.ts","source/data/index.ts","source/data/transaction.ts","source/cache.ts","source/network.ts","source/data/block.ts","source/chain.ts","source/merkle.ts","source/headers.ts","source/application.ts"],"sourcesContent":["// Export all files for now.\nexport * from './data';\nexport * from './network';\n\nexport * from './chain.js';\nexport * from './headers.js';\nexport * from './application.js';\n","export * from './transaction';\nexport * from './block';\n","// Import cache related functions.\nimport { getFromCache, storeInCache } from '../cache';\n\n// Import network related functions.\nimport { fetchTransaction, fetchTransactionProof } from '@electrum-cash/protocol';\n\n// Import the electrum client list.\nimport { electrumClients } from '../network';\n\n// Import types\nimport type { BlockHeight, TransactionHash, TransactionHex, TransactionGetMerkleResponse } from '@electrum-cash/protocol';\n\n/**\n * @module ElectrumApplication\n */\n\n/**\n * Gets a raw transaction as a hex-encoded string.\n * @group Requests\n *\n * @param transactionHash {TransactionHash} - hash of the transaction to use as an identifier.\n *\n * @returns {Promise<TransactionHex>} the transaction as a hex-encoded string.\n */\nexport async function getTransaction(transactionHash: TransactionHash): Promise<TransactionHex>\n{\n\t// Lookup the transaction in local cache.\n\tconst cachedTransactionHex = await getFromCache('transactions', transactionHash);\n\n\t// Return the transaction from cache.\n\tif(cachedTransactionHex)\n\t{\n\t\treturn cachedTransactionHex;\n\t}\n\n\t// Fetch the transaction from the network.\n\t// TODO: Handle clustering!!\n\tconst [ firstElectrumClient ] = electrumClients.values();\n\tconst fetchedTransactionHex = await fetchTransaction(firstElectrumClient, transactionHash);\n\n\t// Store the fetched transaction in local cache.\n\tawait storeInCache('transactions', transactionHash, fetchedTransactionHex);\n\n\t// Return the transaction fetched from the network.\n\treturn fetchedTransactionHex;\n}\n\n/**\n * Gets a transaction inclusion proof.\n * @group Requests\n *\n * @param transactionHash {TransactionHash} - hash of the transaction to use as an identifier.\n * @param blockHeight {BlockHeight} - the height in the blockchain the transaction was included in.\n *\n * @returns {Promise<TransactionGetMerkleResponse | undefined>} the transaction inclusion proof, or undefined if it is still in the mempool.\n */\nexport async function getTransactionInclusionProof(transactionHash: TransactionHash, blockHeight: BlockHeight): Promise<TransactionGetMerkleResponse>\n{\n\t// Determine a unique identity for this transaction proof to make sure it is immutable.\n\t// TODO: This is not correct - for it to be immutable I would need to use the hash, not the height, of the block.\n\tconst transactionProofIdentity = `${transactionHash}:${blockHeight}`;\n\n\t// Lookup the transaction proof in local cache.\n\tconst cachedTransactionProof = await getFromCache('transactionProofs', transactionProofIdentity);\n\n\t// Return the transaction proof from cache.\n\tif(cachedTransactionProof)\n\t{\n\t\treturn cachedTransactionProof;\n\t}\n\n\t// Fetch the transaction proof from the network.\n\t// TODO: Handle clustering!!\n\tconst [ firstElectrumClient ] = electrumClients.values();\n\tconst fetchedTransactionProof = await fetchTransactionProof(firstElectrumClient, transactionHash, blockHeight);\n\n\t// Return undefined if no proof it available.\n\tif(!fetchedTransactionProof)\n\t{\n\t\treturn undefined;\n\t}\n\n\t// Store the fetched transaction proof in local cache.\n\tawait storeInCache('transactionProofs', transactionProofIdentity, fetchedTransactionProof);\n\n\t// Return the transaction proof fetched from the network.\n\treturn fetchedTransactionProof;\n}\n","// Import support for storing data in IndexedDB\n// TODO: use createStore to use a named store so that users who get a dialog to request for more storage space, knows what it's for.\nimport { get, set, createStore } from 'idb-keyval';\n\n/**\n * @module ElectrumCache\n * @ignore\n */\n\n// Default to using persistent database over temporary memory storage.\nlet useMemory = false;\n\ntry\n{\n\t// Attempt to get data from IDB.\n\tget('useIndexedData');\n}\ncatch(error)\n{\n\t// If unsuccessful, switch over to using memory to store data.\n\tuseMemory = true;\n\n\t// Print a warning indicating that cache will not persist across application restarts.\n\t// eslint-disable-next-line no-console\n\tconsole.warn('Unable to access IndexedDB: All data caches will be stored in memory and lost when closing the application.');\n}\n\n// Initialize an empty storage in-memory.\nconst localMemory: Record<string, any> = {};\n\n// Write a key-value pair into memory.\nasync function saveInMemory(group: string, key: string | number, value: any): Promise<void>\n{\n\t// Initialize the storage if necessary.\n\tif(!localMemory[group])\n\t{\n\t\tlocalMemory[group] = new Map();\n\t}\n\n\t// write the key value pair to the storage.\n\tlocalMemory[group].set(key, value);\n}\n\nasync function readFromMemory(group: string, key: string | number): Promise<any>\n{\n\t// Initialize the storage if necessary.\n\tif(!localMemory[group])\n\t{\n\t\tlocalMemory[group] = new Map();\n\t}\n\n\t// write the key value pair to the storage.\n\treturn localMemory[group].get(key);\n}\n\nconst localDatabases: Record<string, any> = {};\n\nasync function saveInDatabase(group: string, key: string | number, value: any): Promise<void>\n{\n\t// Initialize the storage if necessary.\n\tif(!localDatabases[group])\n\t{\n\t\tlocalDatabases[group] = createStore(group, 'data');\n\t}\n\n\t// write the key value pair to the storage.\n\tset(key, value, localDatabases[group]);\n}\n\nasync function readFromDatabase(group: string, key: string | number): Promise<any>\n{\n\t// Initialize the storage if necessary.\n\tif(!localDatabases[group])\n\t{\n\t\tlocalDatabases[group] = createStore(group, 'data');\n\t}\n\n\t// read the key value pair to the storage.\n\treturn get(key, localDatabases[group]);\n}\n\n/**\n * Stores a key-value pair in the indexed DB.\n *\n * @param group   {string}   name of the data set the key-value pair to store belongs in.\n * @param key     {string}   name of the key identifying the data to store within the set.\n * @param value   {any}      data to store in the set, indexed by the key.\n *\n * @returns {Promise<void>}\n */\nexport async function storeInCache(group: string, key: string | number, value: any): Promise<void>\n{\n\tif(useMemory)\n\t{\n\t\t// Pass through the request to the memory storage.\n\t\treturn saveInMemory(group, key, value);\n\t}\n\n\t// Pass through the request to the database storage.\n\treturn saveInDatabase(group, key, value);\n}\n\n/**\n * Gets stored data from the indexed DB.\n *\n * @param group   {string}            name of the data set the stored key-value pair belongs in.\n * @param key     {string | number}   name of the key identifying the stored data within the set.\n *\n * @returns {Promise<any>} the stored data.\n */\nexport async function getFromCache(group: string, key: string | number): Promise<any>\n{\n\tif(useMemory)\n\t{\n\t\treturn readFromMemory(group, key);\n\t}\n\n\treturn readFromDatabase(group, key);\n}\n","// Import network access.\nimport { initializeElectrumClient, sufficientProtocolVersion, requiredProtocolVersion } from '@electrum-cash/protocol';\n\n// Import default servers.\nimport { electrumServers as defaultServers } from '@electrum-cash/servers';\n\n// Import required type definitions.\nimport type { TransportScheme, ElectrumClient } from '@electrum-cash/network';\nimport type { ElectrumServers } from '@electrum-cash/servers';\n\n/**\n * Export the electrum network providers.\n * @ignore\n */\nexport const electrumClients: Map<string, ElectrumClient> = new Map();\n\n/**\n * Connects to the electrum network with the provided servers.\n * @ignore\n *\n * @param application   {string}            name of the application to identify as with the servers.\n * @param transport     {TransportScheme}   which electrum transport to use when connecting with the servers.\n * @param servers       {ElectrumServers}   list of electrum backend servers to connect with.\n */\nexport async function initializeElectrumNetwork(application: string, transport: TransportScheme = 'wss', servers: ElectrumServers = defaultServers): Promise<void>\n{\n\t// Add servers to the cluster.\n\tfor(const server of servers)\n\t{\n\t\t// Ignore any servers that do not support the required version.\n\t\tif(!await sufficientProtocolVersion(server.version))\n\t\t{\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`Skipping ${server.host} due to insufficient version (${server.version} < ${requiredProtocolVersion}).`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Ignore any servers that do not support encrypted websockets.\n\t\tif(!server.transports[transport])\n\t\t{\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`Skipping ${server.host} due to missing '${transport}' transport.`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Skip this servers if it is already part of the network.\n\t\tif(electrumClients.has(server.host))\n\t\t{\n\t\t\tconsole.warn(`Skipping ${server.host} as it is already a part of the initialized network.`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Create an electrum client connected to the server.\n\t\tconst electrumClient = await initializeElectrumClient(application, server.host, server.transports[transport], transport);\n\n\t\t// Add the electrum client to the list of initialized network clients.\n\t\telectrumClients.set(server.host, electrumClient);\n\t}\n}\n\n/**\n * Disconnects from the electrum network and cleans up related resources.\n * @ignore\n */\nexport async function stopElectrumNetwork(): Promise<void>\n{\n\t// Disconnect all servers.\n\tfor(const electrumClient of electrumClients.values())\n\t{\n\t\telectrumClient.disconnect(true);\n\t}\n\n\t// Remove all servers.\n\telectrumClients.clear();\n}\n","// Import cache related functions.\nimport { getFromCache, storeInCache } from '../cache';\n\n// Import network related functions.\nimport { fetchBlockHeaderWithProofFromBlockHeight } from '@electrum-cash/protocol';\n\n// Import utility functions.\nimport { verifyBlockInclusionProof } from '../chain';\nimport { getBlockHashFromHeader } from '../headers';\n\n// Import the electrum client list.\nimport { electrumClients } from '../network';\n\n// Import types\nimport type { BlockHeight, BlockHeaderHash, BlockHeaderHex } from '@electrum-cash/protocol';\n\n// Import the checkpoint necessary to validate block inclusion.\nimport { electrumCheckpoint } from '@electrum-cash/checkpoint';\n\n/**\n * @module ElectrumApplication\n */\n\n/**\n * Gets a raw block header as a hex-encoded string, based on the provided block header hash.\n * @group Requests\n *\n * @param blockHeaderHash {BlockHeaderHash} - hash of the block header to use as an identifier.\n *\n * @returns {Promise<BlockHeaderHex>} the block header as a hex-encoded string.\n */\nexport async function getBlockHeader(blockHeaderHash: BlockHeaderHash): Promise<BlockHeaderHex>\n{\n\t// Shorten the block header hash.\n\tconst shortenedBlockheaderHash = blockHeaderHash.replace(/^0+/, '');\n\n\t// Lookup the block header in local cache.\n\tconst cachedBlockHeaderHex = await getFromCache('blockHeaders', shortenedBlockheaderHash);\n\n\t// Return the block header from cache.\n\tif(cachedBlockHeaderHex)\n\t{\n\t\treturn cachedBlockHeaderHex;\n\t}\n\n\t// Throw an error to indicate that the requested data is currently unavailable.\n\tthrow(new Error(`Could not provide raw block header for ${blockHeaderHash}: Either the block does not exist in the indexer's chain, or the header has not yet been processed locally.`));\n}\n\n/**\n * Gets the block height where the provided block header hash was included in the chain.\n * @group Requests\n *\n * @param blockHeaderHash     {BlockHeaderHash}   hash of the block header to store.\n *\n * @returns {Promise<BlockHeaderHex>}\n */\nexport async function getBlockHeightFromHash(blockHeaderHash: BlockHeaderHash): Promise<BlockHeight>\n{\n\t// Shorten the block header hash.\n\tconst shortenedBlockheaderHash = blockHeaderHash.replace(/^0+/, '');\n\n\t// Lookup the block height in local cache.\n\tconst cachedBlockHeight = await getFromCache('blockheaderHashToHeight', shortenedBlockheaderHash);\n\n\t// Return the block height from cache.\n\tif(cachedBlockHeight)\n\t{\n\t\treturn cachedBlockHeight;\n\t}\n\n\t// Throw an error to indicate that the requested data is currently unavailable.\n\tthrow(new Error(`Could not provide raw block header for ${blockHeaderHash}: Either the block does not exist in the indexer's chain, or the header has not yet been processed locally.`));\n}\n\n/**\n * Gets a raw block header as a hex-encoded string, based on the provided block height.\n * @group Requests\n *\n * @param blockHeight   {BlockHeight}   block height of the block\n *\n * @returns {Promise<BlockHeaderHex>}\n */\nexport async function getBlockHeaderFromHeight(blockHeight: BlockHeight): Promise<BlockHeaderHex>\n{\n\t// Lookup the block header in local cache.\n\tconst cachedBlockHeaderHash = await getFromCache('blockheaderHeightToHash', blockHeight);\n\n\t// Return the block header from cache.\n\tif(cachedBlockHeaderHash)\n\t{\n\t\t// NOTE: The cached header will be shortened with leading zeroes removed.\n\t\t//       These are not re-added here since this function would then need to remove them.\n\t\treturn getBlockHeader(cachedBlockHeaderHash);\n\t}\n\n\t// Throw an error if we are unable to validate this header.\n\tif(blockHeight > electrumCheckpoint.height)\n\t{\n\t\tthrow(new Error(`Could not validate a block header on height ${blockHeight}: The requested header is ahead of the current checkpoint at height ${electrumCheckpoint.height}`));\n\t}\n\n\t// Fetch the full block header and merkle proof for this height.\n\t// NOTE: the result of this network call is not cached, since it is expected to not be needed again in the future.\n\t// TODO: Handle clustering!!\n\tconst [ firstElectrumClient ] = electrumClients.values();\n\tconst { branch, header, root } = await fetchBlockHeaderWithProofFromBlockHeight(firstElectrumClient, blockHeight, electrumCheckpoint.height);\n\n\t// Hash the fetched block header\n\tconst fetchedBlockHeaderHash = await getBlockHashFromHeader(header);\n\tconst shortenedBlockheaderHash = fetchedBlockHeaderHash.replace(/^0+/, '');\n\n\ttry\n\t{\n\t\t// Validate chain inclusion\n\t\tawait verifyBlockInclusionProof(fetchedBlockHeaderHash, blockHeight, branch, root);\n\n\t\t// Store the block header.\n\t\tawait storeInCache('blockHeaders', shortenedBlockheaderHash, header);\n\t}\n\tcatch(error)\n\t{\n\t\t// Re-throw the error with more context.\n\t\tthrow(new Error(`Failed to validate block header ${fetchedBlockHeaderHash} at height ${blockHeight}: validation of block inclusion in checkpoint at height ${electrumCheckpoint.height} failed.`));\n\t}\n\n\t// Store the block header in both orientations.\n\t// NOTE: The height->hash is considered immutable since the block inclusion proof for the trusted checkpoint passed.\n\tawait storeInCache('blockheaderHeightToHash', blockHeight, shortenedBlockheaderHash);\n\tawait storeInCache('blockheaderHashToHeight', shortenedBlockheaderHash, blockHeight);\n\n\t// Return the fetched block header.\n\treturn header;\n}\n","// Import utility functions.\nimport { hexToBin } from '@bitauth/libauth';\nimport { verifyMerkleProof } from './merkle';\n\nimport type { BlockHeaderHash, BlockHeight, TransactionHash } from '@electrum-cash/protocol';\n\n/**\n * @module Blockchain\n * @ignore\n */\n\n/**\n * Validates the merkle proof used to verify block inclusion in the chain defined by a trusted checkpoint.\n *\n * @ignore\n */\nexport async function verifyBlockInclusionProof(blockHash: BlockHeaderHash, blockHeight: BlockHeight, merkleBranches: Array<string>, merkleRootHash: string): Promise<void>\n{\n\t// Fix block hash endianness.\n\tconst dataHash = hexToBin(blockHash).reverse();\n\n\t// Use the block height as the data position in the set.\n\tconst dataPosition = blockHeight;\n\n\t// Reverse endianness of the branches\n\tconst reversedMerkleBranches = merkleBranches.map((branch) => hexToBin(branch).reverse());\n\n\t// Convert the merkle root to binary format, reversing the endianness provided.\n\t// NOTE: Electrum servers provide the merkle root for block chain-inclusion proofs in the opposite endianness.\n\tconst reversedMerkleRoot = hexToBin(merkleRootHash).reverse();\n\n\t// Call verifyMerkleProof\n\tawait verifyMerkleProof(dataHash, dataPosition, reversedMerkleBranches, reversedMerkleRoot);\n}\n\n/**\n * Validates the merkle proof used to verify transaction inclusion in a provided block.\n *\n * @ignore\n */\nexport async function verifyTransactionInclusionProof(transactionHash: TransactionHash, merklePosition: number, merkleBranches: Array<string>, merkleRootHash: string): Promise<void>\n{\n\t// Fix block hash endianness.\n\tconst dataHash = hexToBin(transactionHash).reverse();\n\n\t// Use the block height as the data position in the set.\n\tconst dataPosition = merklePosition;\n\n\t// Reverse endianness of the branches\n\tconst reversedMerkleBranches = merkleBranches.map((branch) => hexToBin(branch).reverse());\n\n\t// Convert the merkle root to binary format, keeping the endianness provided.\n\t// NOTE: Electrum servers provide the merkle root for transaction block-inclusion proofs in the expected endianness.\n\tconst reversedMerkleRoot = hexToBin(merkleRootHash);\n\n\t// Call verifyMerkleProof\n\tawait verifyMerkleProof(dataHash, dataPosition, reversedMerkleBranches, reversedMerkleRoot);\n}\n","// Import utility functions.\nimport { binToHex, sha256 } from '@bitauth/libauth';\n\n/**\n * @module Utilities.Merkle\n * @ignore\n */\n\n/**\n * Verifies that a provided data hash at a given position is a part of a merkle tree.\n *\n * @param dataHash       {Uint8Array}          ...\n * @param dataPosition   {Uint8Array}          ...\n * @param merkleBranches {Array<Uint8Array>}   ...\n * @param merkleRootHash {Uint8Array}          ...\n *\n * @throws an error if the computed root hash does not match the provided merkle root hash.\n *\n * @returns {Promise<void>}\n */\nexport async function verifyMerkleProof(dataHash: Uint8Array, dataPosition: number, merkleBranches: Array<Uint8Array>, merkleRootHash: Uint8Array): Promise<void>\n{\n\t// Copy the target block hash as the starting point in the merkle branch.\n\tlet rootHashCandidate = dataHash;\n\n\t// Use the data position in the block as the merkle path, determining the orientation of the hashes at each step.\n\tlet merklePath = dataPosition;\n\n\t// For each branch in the merkle proof..\n\tfor(const branch of merkleBranches)\n\t{\n\t\t// Assume the default merkle orientation, where our data is on the left side of the branch.\n\t\tlet merkleOrientation = [ ...rootHashCandidate, ...branch ];\n\n\t\t// Update merkle orientation if the merkle path indicates that we should be on the right side of the branch.\n\t\tif(merklePath % 2)\n\t\t{\n\t\t\tmerkleOrientation = [ ...branch, ...rootHashCandidate ];\n\t\t}\n\n\t\t// Update the root hash candidate by hashing the merkle nodes at this branch in the tree.\n\t\trootHashCandidate = sha256.hash(sha256.hash(merkleOrientation as unknown as Uint8Array));\n\n\t\t// Bit-shift out the right-most position in the merkle path as we've used it.\n\t\tmerklePath >>= 1;\n\t}\n\n\t// Throw an error if the computed root hash does not match the expected merkle root.\n\tif(binToHex(rootHashCandidate) !== binToHex(merkleRootHash))\n\t{\n\t\tthrow(new Error(`Provided dataHash (${binToHex(dataHash)}) either does not belong at the specified position (${dataPosition}) or does not belong in the the specified data set (${binToHex(merkleRootHash)}).`));\n\t}\n}\n","// ...\nimport { hexToBin, binToHex, binToNumberUint32LE, hash256 } from '@bitauth/libauth';\n\n// cspell:ignore uncompress\n\n// // Import Bitcoin Cash protocol constants.\n// import\n// {\n// \tMAX_TARGET_EXPONENT_DATA,\n// \tMIN_TARGET_SIGNIFICAND,\n// \tMAX_TARGET_SIGNIFICAND,\n// \tMAX_COMPRESSED_DIFFICULTY_TARGET,\n// \tASERT_ACTIVATION_TIME_MTP,\n// \tCW144_ACTIVATION_HEIGHT,\n// } from './protocol';\n//\n// import type { BlockHeaderObject } from './interfaces';\n//\n// /** @module Blockchain **/\n//\n// /**\n//  * Parses a hex-encoded block header string into parts.\n//  *\n//  * @param blockHeaderHex   {string}   block header to parse, as a hex-encoded string.\n//  *\n//  * @returns {Promise<BlockHeaderObject>}\n//  */\n// export async function parseBlockHeader(blockHeaderHex: string): Promise<BlockHeaderObject>\n// {\n// \t// Define the valid block header length for a hex-encoded header string.\n// \tconst validLength = 80 * 2;\n//\n// \t// Throw an error if the provided block header has an incorrect size.\n// \tif(blockHeaderHex.length !== validLength)\n// \t{\n// \t\tthrow(new Error(`Could not parse ${blockHeaderHex.length} byte block header, should be ${validLength} bytes.`));\n// \t}\n//\n// \t// Extract the version number for the header.\n// \tconst version = parseInt(\"0x\" + binToNumberUint32LE(hexToBin(blockHeaderHex.substring(0, 8))).toString(16), 16);\n//\n// \t// Extract the hash of the previous block in the chain.\n// \tconst previousBlockHash = blockHeaderHex.substring(8, 72);\n//\n// \t// Extract the merkle root of the transactions in the block.\n// \tconst merkleRoot = blockHeaderHex.substring(72, 136);\n//\n// \t// Extract the unix timestamp.\n// \t// TODO: Verify if this is signed or unsigned.\n// \tconst timestamp = binToNumberUint32LE(hexToBin(blockHeaderHex.substring(136, 144)));\n//\n// \t// Extract and parse the target.\n// \tconst compressedTarget = hexToBin(blockHeaderHex.substring(144, 152));\n//\n// \t// Extract the nonce.\n// \tconst nonce = blockHeaderHex.substring(152, 160);\n//\n// \t// Return the parsed block headers.\n// \treturn { version, previousBlockHash, merkleRoot, timestamp, compressedTarget, nonce };\n// };\n//\n// export async function calculateDifficultTarget(blockHeader: string): Promise<Uint8Array>\n// {\n// \t// Determine the block hash for the provided header.\n// \tconst currentBlockHash = await getBlockHashFromHeader(blockHeader);\n//\n// \t// Determine block height for the block header provided.\n// \tconst currentBlockHeight = await getBlockHeightByHash();\n//\n// \t// TODO: Return an initial difficulty target if no history exist before\n// \tif(currentBlockHeight === 0)\n// \t{\n// \t\treturn MAX_COMPRESSED_DIFFICULTY_TARGET;\n// \t}\n//\n// \t// Parse the provided block header.\n// \tconst { previousBlockHash, timestamp: currentTimestamp  } = await parseBlockHeader(blockHeader);\n//\n// \t// Fetch the previous block to use for comparison.\n// \tconst previousBlockHeader = await getBlockHeaderByHash(previousBlockHash);\n//\n// \t// Parse the previous block header.\n// \tconst { timestamp: previousTimestamp } = await parseBlockHeader(previousBlockHeader);\n//\n// \t// Determine the block height for the previous block.\n// \tconst previousBlockHeight = currentBlockHeight - 1;\n//\n// \t// TODO: Figure out how to get the median time past.\n// \tconst medianTimePast = await getMedianTimePast(currentTimestamp, previousTimestamp);\n//\n// \t// TODO: Figure out where to store protocol constants.\n// \t// TODO:\n// \tif(medianTimePast >= ASERT_ACTIVATION_TIME_MTP)\n// \t{\n// \t\t// TODO: Figure out what parameters to send to this.\n// \t\t// return calculateAsertDifficultTarget();\n// \t}\n//\n// \tif(previousBlockHeight >= CW144_ACTIVATION_HEIGHT)\n// \t{\n// \t\t// return calculateCW44DifficultTarget();\n// \t}\n//\n// \t// TODO: Handle EDA.\n// \t// TODO: Handle Legacy.\n// };\n//\n// // bits_to_work\n// export async function deriveWorkFromCompressedTarget()\n// {\n// \t// return (1 << 256) // (bits_to_target(bits) + 1)\n// }\n//\n// // target_to_bits\n// export async function compressTarget(target: number): Promise<Uint8Array>\n// {\n// \t// Limit the target to stay below the max allowed target.\n// \tconst boundedTarget = Math.min(target, await uncompressTarget(MAX_COMPRESSED_DIFFICULTY_TARGET));\n//\n// \t//\n// \tconst indirectExponent = (BIT_LENGTH_OF(boundedTarget) + 7) / 8;\n//\n// \tif(indirectExponent <= 3)\n// \t{\n//\n// \t}\n// /*\n//     mask64 = 0xffffffffffffffff\n//     if size <= 3:\n//         compact = (target & mask64) << (8 * (3 - size))\n//     else:\n//         compact = (target >> (8 * (size - 3))) & mask64\n//\n//     if compact & 0x00800000:\n//         compact >>= 8\n//         size += 1\n//     assert compact == (compact & 0x007fffff)\n//     assert size < 256\n//     return compact | size << 24\n// */\n// }\n//\n// // bits_to_target\n// export async function uncompressTarget(compressedTarget: Uint8Array): Promise<number>\n// {\n// \t// Split the compressed target into the indirect exponent and the significand/mantissa.\n// \t// TODO: Convert these to numbers.\n// \tconst indirectExponent = compressedTarget.slice(0, 1);\n// \tconst significand = compressedTarget.slice(1);\n//\n// \t// Verify that the indirect exponent does not go above the maximum allowed value.\n// \tif(indirectExponent > MAX_TARGET_EXPONENT_DATA)\n// \t{\n// \t\tthrow(new Error(`Cannot uncompress target, provided indirect exponent (${indirectExponent}) is higher than maximum (${MAX_TARGET_EXPONENT_DATA}).`));\n// \t}\n//\n// \t// Verify that the significand does not go below the minimum allowed value.\n// \tif(significand < MIN_TARGET_SIGNIFICAND)\n// \t{\n// \t\tthrow(new Error(`Cannot uncompress target, provided significand (${significand}) is lower than minimum (${MIN_TARGET_SIGNIFICAND}).`));\n// \t}\n//\n// \t// Verify that the significand does not go above the maximum allowed value.\n// \tif(significand > MAX_TARGET_SIGNIFICAND)\n// \t{\n// \t\tthrow(new Error(`Cannot uncompress target, provided significand (${significand}) is higher than maximum (${MAX_TARGET_SIGNIFICAND}).`));\n// \t}\n//\n// \t// Return the uncompressed target.\n// \tif(indirectExponent < 3)\n// \t{\n// \t\treturn significand >> (8 * (3 - indirectExponent))\n// \t}\n// \telse\n// \t{\n// \t\treturn significand << (8 * (indirectExponent - 3))\n// \t}\n//\n// }\n//\n// export async function getMedian(list: number[]): Promise<number>\n// {\n// \t// If the provided list has no numbers in it..\n// \tif(list.length === 0)\n// \t{\n// \t\t// Return zero as the median.\n// \t\treturn 0;\n// \t}\n//\n// \t// Sort the list of numbers.\n// \tlist.sort((a, b) => a - b);\n//\n// \t// Calculate the middle index of the timestamps.\n// \tconst middleIndex = Math.floor(list.length / 2);\n//\n// \t// If two entries share the middle index, return the average of the two numbers.\n// \tif(middleIndex % 2)\n// \t{\n// \t\treturn (list[middleIndex - 1] + list[middleIndex]) / 2;\n// \t}\n//\n// \t// If there is only a single entry in the midpoint, return it.\n// \treturn list[middleIndex];\n// }\n//\n// export async function getMedianTimePast(height: number, headers?: string): Promise<number>\n// {\n// \tif(!headers)\n// \t{\n// \t\t// TODO: fetch the headers.\n// \t}\n//\n// \t// TODO: Split the chunked header list into an array of hex-encoded headers.\n// \t// const headers =\n//\n// \t// TODO: Extract the timestamps from each header.\n// \t// const timestamps = headers.map(header => )\n//\n// \t// Return the median value of the timestamps.\n// \treturn await getMedian(timestamps);\n// }\n//\n// export async function getBlockHashFromHeader(header: string): Promise<void>\n// {\n//\n// }\n//\n\n/**\n * TODO: Document me.\n * @group Requests\n */\nexport async function getBlockHashFromHeader(header: string): Promise<string>\n{\n\treturn binToHex(hash256(hexToBin(header)).reverse());\n}\n\n/**\n * TODO: Document me.\n * @group Requests\n */\nexport async function getMerkleRootFromHeader(header: string): Promise<string>\n{\n\treturn header.substring(72, 136);\n}\n","//\nimport { EventEmitter } from 'events';\n\n// Import network access from electrum-cash.\nimport { electrumServers as defaultServers } from '@electrum-cash/servers';\nimport { electrumCheckpoint as defaultCheckpoint } from '@electrum-cash/checkpoint';\n\n// Import electrum network abstractions\nimport { electrumClients, initializeElectrumNetwork } from './network';\n\nimport\n{\n\tfetchBlockHeaders,\n\tfetchHistory,\n\tfetchTransactionBlockHeight,\n\tsubscribeToBlockheaderUpdates,\n\tsubscribeToAddressUpdates,\n\tsubscribeToTransactionUpdates,\n\tsubscribeToDoublespendUpdates,\n} from '@electrum-cash/protocol';\n\n// ..\nimport { storeInCache, getFromCache } from './cache';\nimport { getBlockHashFromHeader, getMerkleRootFromHeader } from './headers';\nimport { getTransaction, getTransactionInclusionProof, getBlockHeaderFromHeight } from './data';\nimport { verifyTransactionInclusionProof } from './chain';\n\n// Import required type definitions.\nimport type { TransportScheme } from '@electrum-cash/network';\nimport type { ElectrumServers } from '@electrum-cash/servers';\n\n// Import electrum and blockchain related type information.\nimport type { BlockHeight, BlockHeaderHex, HeadersSubscribeNotification, Address, AddressStatus, AddressGetHistoryResponse, AddressSubscribeNotification, TransactionHash, TransactionSubscribeNotification, TransactionDsProofNotification } from '@electrum-cash/protocol';\n\n// Import thread locking library to control order or operations.\nimport { Mutex } from 'async-mutex';\n\n/**\n * @module ElectrumApplication\n */\n\n// ...\n// TODO: Move into separate module and expose via get/set functions.\nconst TRANSACTION_IS_UNKNOWN = 0;\nconst TRANSACTION_IS_RECEIVED = 1;\nconst TRANSACTION_IS_DOUBLESPENT = 2;\nconst TRANSACTION_IS_VERIFIED = 3;\n\n// Initialize an empty in-memory transaction state tracker.\n// TODO: Move into separate module and expose via get/set functions.\nconst internalTransactionState: Record<TransactionHash, number> = {};\n\n// Initialize a mutex lock for the synchronization of block headers.\nconst headerSynchronizationLock = new Mutex();\n\n// Initialize a default empty chain status.\n// TODO: Add mechanic to allow clients to access current state without needing to respond to an event.\nlet currentChainStatus = { verifiedHeight: 0, verifiedPercent: 0 };\n\n/**\n* @event ChainStatus\n* @group Events\n*\n* @property {number} verifiedHeight  - number of blocks that been verified to be part of the block chain.\n* @property {number} verifiedPercent - percentage of blocks that have been verified to be included in the chain.\n*/\n\n/**\n* @event BlockReceived\n* @group Events\n*\n* @property {BlockHeaderHash} blockHash - hash of the received blocks header.\n* @property {BlockHeight} blockHeight - height at which the block was verified to be included in the chain.\n*/\n\n/**\n* @event BlockVerified\n* @group Events\n*\n* @property {BlockHeaderHash} blockHash   - hash of the verified blocks header.\n* @property {BlockHeight} blockHeight - height at which the block was verified to be included in the chain.\n*/\n\n/**\n* @event TransactionReceived\n* @group Events\n*\n* @property {TransactionHash} transactionHash - hash of the received transaction.\n*/\n\n/**\n* @event TransactionVerified\n* @group Events\n*\n* @property {TransactionHash} transactionHash - hash of the transaction that has been verified to be included in the chain.\n* @property {BlockHeight} blockHeight     - height at which the transaction was verified to be included in the chain.\n*/\n\n/**\n* TODO: Double-check the properties here.\n* @event TransactionDoubleSpendDetected\n* @group Events\n*\n* @property {TransactionHash} transactionHash - hash of the transaction that has been verified to be included in the chain.\n* @property {doubleSpendProofHash} blockHeight     - height at which the transaction was verified to be included in the chain.\n*/\n\n/**\n* Notification that the status of an address history might have changed.\n*\n* @event AddressUpdateReceived\n* @group Events\n*\n* @property {Address} address       - address relevant to the update notification.\n* @property {AddressStatus} status  - address status hash.\n*/\n\n/**\n * Set up an event emitter for SPV related events.\n */\nconst electrumEvents = new EventEmitter();\n\n/**\n * Subscribes to block updates and emits events when the chain status updates.\n * @group Monitoring\n *\n * @emits BlockReceived\n * @emits BlockVerified\n * @emits ChainStatus\n */\nexport async function monitorBlockchain(): Promise<void>\n{\n\t// For each server we are connected to..\n\tfor(const electrumClient of electrumClients.values())\n\t{\n\t\t// Set up a subscription to monitor for blockchain header updates.\n\t\tawait subscribeToBlockheaderUpdates(electrumClient);\n\t}\n}\n\n/**\n * Subscribes to address updates and emits events when the address history changes.\n *\n * Note that any transaction that relates to the address history, will automatically be monitored as well.\n * @group Monitoring\n *\n * @emits AddressBalance?\n * @emits AddressHistory?\n *\n * @param address {Address} - The address to monitor for changes.\n */\nexport async function monitorAddress(address: Address): Promise<void>\n{\n\t// For each server we are connected to..\n\tfor(const electrumClient of electrumClients.values())\n\t{\n\t\t// Set up a subscription to monitor for the address for status updates.\n\t\tawait subscribeToAddressUpdates(electrumClient, address);\n\t}\n}\n\n/**\n * Subscribes to transaction updates and emits events when the transaction status changes.\n * @group Monitoring\n *\n * @emits TransactionReceived\n * @emits TransactionVerified\n * @emits TransactionDoubleSpendDetected\n *\n * @param transactionHash {TransactionHash} - The transaction to monitor for changes.\n */\nexport async function monitorTransaction(transactionHash: TransactionHash): Promise<void>\n{\n\t// For each server we are connected to..\n\tfor(const electrumClient of electrumClients.values())\n\t{\n\t\t// Set up a subscription to monitor for block inclusion.\n\t\tawait subscribeToTransactionUpdates(electrumClient, transactionHash);\n\n\t\t// Also monitor for double-spend proofs for the transaction.\n\t\tawait subscribeToDoublespendUpdates(electrumClient, transactionHash);\n\t}\n}\n\n/**\n * Utility function to calculate a percentage for chain recovery status.\n * @ignore\n */\nasync function calculateChainRecoveryPercent(internalBlockHeight: BlockHeight, externalBlockHeight: BlockHeight): Promise<number>\n{\n\treturn ((internalBlockHeight - defaultCheckpoint.height) / (externalBlockHeight - defaultCheckpoint.height)) * 100;\n}\n\n/**\n * Handles incoming block headers by verifying their validity, storing them in a cache and emitting related events.\n * @ignore\n */\nasync function processBlockHeader(blockHeight: BlockHeight, blockHeader: BlockHeaderHex, targetBlockHeight: BlockHeight): Promise<void>\n{\n\t// Calculate the full and shortened hash of the block header.\n\tconst processedBlockheaderHash = await getBlockHashFromHeader(blockHeader);\n\tconst shortenedBlockheaderHash = processedBlockheaderHash.replace(/^0+/, '');\n\n\t// Store block height to indicate the block header was successfully received.\n\tawait storeInCache('chainState', 'currentHeight', blockHeight);\n\n\t// Send a signal indicating that we have received a new block.\n\telectrumEvents.emit('BlockReceived', { blockHeight, blockHash: processedBlockheaderHash });\n\n\t// TODO: Validate chainwork? (processBlockHeader is only called from subscription responses, which should always be above the checkpoint height)\n\n\t// Store the blocks header, height and hash in the local cache.\n\tawait storeInCache('blockHeaders', shortenedBlockheaderHash, blockHeader);\n\tawait storeInCache('blockheaderHeightToHash', blockHeight, shortenedBlockheaderHash);\n\tawait storeInCache('blockheaderHashToHeight', shortenedBlockheaderHash, blockHeight);\n\n\t// Send a signal indicating that we have validated a new block.\n\t// TODO: Verify that this is all information we want to send here.\n\telectrumEvents.emit('BlockVerified', { blockHeight, blockHash: processedBlockheaderHash });\n\n\t// Store block height to indicate the block header was successfully verified.\n\tawait storeInCache('chainState', 'verifiedHeight', blockHeight);\n\n\t// Calculate the current chain recovery percent after accepting the block as valid.\n\tconst chainRecoveryPercent = Math.floor(await calculateChainRecoveryPercent(blockHeight, targetBlockHeight));\n\n\t// If the recovery state has changed significantly enough..\n\tif(chainRecoveryPercent !== currentChainStatus.verifiedPercent)\n\t{\n\t\t// Update the current chain status.\n\t\tcurrentChainStatus =\n\t\t{\n\t\t\tverifiedHeight: blockHeight,\n\t\t\tverifiedPercent: chainRecoveryPercent,\n\t\t};\n\n\t\t// Issue an event indicating that chain status has been updated.\n\t\t// TODO: Decide what numbers and names to emit.\n\t\telectrumEvents.emit('ChainStatus', currentChainStatus);\n\t}\n}\n\n/**\n * Handles incoming transaction updates by validating their block inclusion status and storing them in a cache and emitting related events.\n * @private\n */\nasync function processTransactionUpdate(transactionHash: TransactionHash, blockHeight?: BlockHeight): Promise<void>\n{\n\t// Handle this transaction, if it has not been received before.\n\tif((typeof internalTransactionState[transactionHash] === 'undefined') || (internalTransactionState[transactionHash] < TRANSACTION_IS_RECEIVED))\n\t{\n\t\t// Get the transaction to ensure it gets cached.\n\t\tawait getTransaction(transactionHash);\n\n\t\t// Emit event for the transaction, as we haven't seen it before.\n\t\telectrumEvents.emit('TransactionReceived', transactionHash);\n\n\t\t// Set the internal tracking of this transactions state to unverified.\n\t\tinternalTransactionState[transactionHash] = TRANSACTION_IS_RECEIVED;\n\t}\n\n\t// NOTE: Double-spend state is between RECEIVED and VERIFIED, but is handled by processElectrumNotifications().\n\n\t// Verify this transactions block inclusion, if it has not been verified before.\n\tif((typeof internalTransactionState[transactionHash] === 'undefined') || (internalTransactionState[transactionHash] < TRANSACTION_IS_VERIFIED))\n\t{\n\t\t// Use the provided blockheight, or fetch the blockheight from the network if necessary.\n\t\t// TODO: Handle clustering!!\n\t\tconst [ firstElectrumClient ] = electrumClients.values();\n\t\tconst someHeight = blockHeight || await fetchTransactionBlockHeight(firstElectrumClient, transactionHash);\n\n\t\t// Skip block inclusion validation for this transaction as it is either unknown, or in the mempool.\n\t\t// NOTE: Electrum provides 'null' for unknown, and a height of '0' or less for in-mempool.\n\t\tif((someHeight === null) || (someHeight <= 0))\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t// Get transactions block inclusion proof since it is not in the mempool.\n\t\tconst { pos, merkle } = await getTransactionInclusionProof(transactionHash, blockHeight);\n\n\t\t// Get the blocks header in order to verify the transaction inclusion proof.\n\t\tconst blockHeaderHex = await getBlockHeaderFromHeight(blockHeight);\n\n\t\t// Parse the blockheader to extract the merkle root.\n\t\tconst root = await getMerkleRootFromHeader(blockHeaderHex);\n\n\t\t// Verify that the transaction is included in the block.\n\t\tawait verifyTransactionInclusionProof(transactionHash, pos, merkle, root);\n\n\t\t// Emit event for validated transaction proof, if we haven't already?\n\t\telectrumEvents.emit('TransactionVerified', transactionHash);\n\n\t\t// Set the internal tracking of this transactions state to unverified.\n\t\tinternalTransactionState[transactionHash] = TRANSACTION_IS_VERIFIED;\n\t}\n}\n\n/**\n * Handles incoming address updates by tracking the address history, unspent outputs and balances, storing transactions in a cache and emitting related events.\n * @private\n */\nasync function processAddressUpdate(address: Address): Promise<void>\n{\n\telectrumEvents.emit('AddressUpdate', address);\n\n\t// TODO: Fetch history since last update (or all if this is the first request)\n\t// TODO: Handle clustering!!\n\tconst [ firstElectrumClient ] = electrumClients.values();\n\tconst updatedAddressHistory = await fetchHistory(firstElectrumClient, address);\n\n\t// Set up a list of empty transaction update promises.\n\tconst transactionUpdatePromises = [];\n\n\t// Iterate over history to:\n\tfor(const { tx_hash: transactionHash, height } of updatedAddressHistory)\n\t{\n\t\t// Monitor the transaction if it is still in the mempool.\n\t\tif(height <= 0)\n\t\t{\n\t\t\t// Request updates for this transaction in the future.\n\t\t\t// NOTE: In rare cases, this might monitor an already monitored transactions and that is not a problem.\n\t\t\t// NOTE: We do not await this in order to ensure fast processing transaction histories.\n\t\t\tmonitorTransaction(transactionHash);\n\t\t}\n\n\t\t// Process the transaction as if it a transaction update event was emitted.\n\t\t// NOTE: We do not await this in order to ensure fast processing of transaction histories.\n\t\ttransactionUpdatePromises.push(processTransactionUpdate(transactionHash, height));\n\t}\n\n\t// Wait for all transaction updates to complete.\n\tawait Promise.all(transactionUpdatePromises);\n\n\t// TODO: Use the updated address data to:\n\t// - determine a current UTXO set for the address\n\t// - determine a current balance based on the UTXO set.\n\t//   · emit event at end of process if balance changed\n}\n\n/**\n * Requests block headers in a loop until the internal and external block height is synchronized.\n * @ignore\n */\nasync function synchronizeBlockHeaders(targetBlockHeight: BlockHeight, targetBlockheader: BlockHeaderHex): Promise<void>\n{\n\t// Throw an error if the reported chain height is less than the checkpoint height.\n\tif(targetBlockHeight < defaultCheckpoint.height)\n\t{\n\t\tthrow(new Error(`Network blockchain height (${targetBlockHeight}) is lower than the known-good checkpoint height (${defaultCheckpoint.height}).`));\n\t}\n\n\t// If synchronization is currently ongoing, do nothing.\n\tif(await headerSynchronizationLock.isLocked())\n\t{\n\t\treturn;\n\t}\n\n\t// Lock the header synchronization lock to prevent concurrent synchronization of headers.\n\tconst unlock = await headerSynchronizationLock.acquire();\n\n\ttry\n\t{\n\t\t// Get the internal block height from cache.\n\t\tlet internalBlockHeight = await getFromCache('chainState', 'currentHeight');\n\n\t\t// While there are block header to synchronize between our internal state and the provided block..\n\t\twhile(internalBlockHeight < targetBlockHeight)\n\t\t{\n\t\t\t// Determine what the next block height will be.\n\t\t\tconst startingBlockHeight = internalBlockHeight + 1;\n\n\t\t\t// Count the number of blocks there are to download.\n\t\t\tconst remainingBlocks = targetBlockHeight - internalBlockHeight;\n\n\t\t\t// Batch-fetch up to 1000 headers from the checkpointHeight towards the current tip and process them.\n\t\t\t// TODO: Handle clustering!!\n\t\t\tconst [ firstElectrumClient ] = electrumClients.values();\n\t\t\tconst blockHeaders = await fetchBlockHeaders(firstElectrumClient, startingBlockHeight, Math.min(1000, remainingBlocks));\n\n\t\t\t// Process each of the new block headers\n\t\t\tfor(const blockHeader of blockHeaders)\n\t\t\t{\n\t\t\t\t// Determine what the next block height will be.\n\t\t\t\tconst nextBlockHeight = internalBlockHeight + 1;\n\n\t\t\t\t// Process the provided block header as the next in the chain.\n\t\t\t\tawait processBlockHeader(nextBlockHeight, blockHeader, targetBlockHeight);\n\n\t\t\t\t// Bump the internal block height to the next block.\n\t\t\t\tinternalBlockHeight = nextBlockHeight;\n\t\t\t}\n\t\t}\n\n\t\t// Process the provided block header, as if it was the most recent block in the chain.\n\t\tawait processBlockHeader(targetBlockHeight, targetBlockheader, targetBlockHeight);\n\t}\n\tcatch(error)\n\t{\n\t\t// TODO: Handle errors better.\n\t}\n\tfinally\n\t{\n\t\t// Unlock the thread so further synchronization can happen.\n\t\tunlock();\n\t}\n}\n\n/**\n * Handler function for all electrum events.\n *\n * This function determines what type of events has happened and emits relevant signals.\n *\n * @private\n */\nasync function processElectrumEvents(event: any): Promise<void>\n{\n\t// Expose all electrum events.\n\telectrumEvents.emit(event);\n}\n\n/**\n * TODO: Document me.\n */\nasync function processAddressNotification(notification: AddressSubscribeNotification): Promise<void>\n{\n\t// Extract the address and status from the notification.\n\tconst { params } = notification;\n\tconst [ address, status ] = params;\n\n\t// TODO: Do nothing if the status has not changed since the last event.\n\n\t// Process the address update.\n\tawait processAddressUpdate(address);\n}\n\n/**\n * TODO: Document me.\n */\nasync function processHeaderNotification(notification: HeadersSubscribeNotification): Promise<void>\n{\n\t// Extract the block header and height from the notification.\n\tconst { params } = notification;\n\tconst { height, hex } = params[0];\n\n\t// Synchronize up to this block in the chain.\n\tsynchronizeBlockHeaders(height, hex);\n}\n\n/**\n * TODO: Document me.\n */\nasync function processTransactionNotification(notification: TransactionSubscribeNotification): Promise<void>\n{\n\t// Extract the transaction hash and inclusion height from the notification.\n\tconst { params } = notification as TransactionSubscribeNotification;\n\tconst [ transactionHash, inclusionHeight ] = params;\n\n\t// Process the transaction update.\n\tawait processTransactionUpdate(transactionHash, inclusionHeight);\n}\n\n/**\n * TODO: Document me.\n */\nasync function processDoublespendNotification(notification: TransactionDsProofNotification): Promise<void>\n{\n\t// Extract the double spend proof from the notification.\n\tconst { params } = notification;\n\tconst [ doubleSpendProof ] = params;\n\n\t// Update internal transaction state, but only if it has not been verified in a block.\n\tinternalTransactionState[doubleSpendProof.txid] = Math.max(TRANSACTION_IS_DOUBLESPENT, internalTransactionState[doubleSpendProof.txid]);\n\n\t// Send a signal indicating that the provided transaction hash has been doublespent.\n\t// NOTE: Double spend proofs are taken into account for the transaction and address status updates, so no further action is necessary.\n\telectrumEvents.emit('TransactionDoubleSpendDetected', { transactionHash: doubleSpendProof.txid, doubleSpendProofHash: doubleSpendProof.dspid });\n}\n\n/**\n * Initializes a light client that implements the Simple Payment Verification protocol transparently for the user.\n * @group Setup\n *\n * @param application   {string}            name of the application to identify as with the servers.\n * @param transport     {TransportScheme}   which electrum transport to use when connecting with the servers.\n * @param servers       {ElectrumServers}   list of electrum backend servers to connect with.\n *\n * @returns an event emitter for the electrum application events.\n */\nexport async function initializeElectrumApplication(application: string, transport: TransportScheme = 'wss', servers: ElectrumServers = defaultServers): Promise<EventEmitter>\n{\n\t// Create a connection with the electrum network.\n\tawait initializeElectrumNetwork(application, transport, servers);\n\n\t// For each server we are connected to..\n\tfor(const electrumClient of electrumClients.values())\n\t{\n\t\t// // Listen for notifications\n\t\telectrumClient.on('blockchain.headers.subscribe', processHeaderNotification);\n\t\telectrumClient.on('blockchain.address.subscribe', processAddressNotification);\n\t\telectrumClient.on('blockchain.transaction.subscribe', processTransactionNotification);\n\t\telectrumClient.on('blockchain.transaction.dsproof.subscribe', processDoublespendNotification);\n\n\t\t// Listen for network events.\n\t\t// NOTE: The connected event is not yet hooked up upstreams\n\t\t// electrumClients.on('connected', processElectrumEvents);\n\t\t// electrumClients.on('disconnected', processElectrumEvents);\n\t}\n\n\t// Resume validation from the current chain state.\n\tconst internalBlockHeight = await getFromCache('chainState', 'currentHeight');\n\n\t// Reset to the checkpoint height if no chain state exist.\n\tif(!internalBlockHeight)\n\t{\n\t\tawait storeInCache('chainState', 'currentHeight', defaultCheckpoint.height);\n\t}\n\n\t// Initialize the current chain status to our internal height, keeping the verified percent to 0 for now.\n\tcurrentChainStatus.verifiedHeight = internalBlockHeight || defaultCheckpoint.height;\n\n\t// Issue an event with our initial chain status.\n\telectrumEvents.emit('ChainStatus', currentChainStatus);\n\n\t// TODO: Get and validate internal state (checkpoint, blockheight, chainwork etc)\n\n\t// Set up tracking for blockheader events.\n\tawait monitorBlockchain();\n\n\t// Return the event emitter.\n\treturn electrumEvents;\n}\n"],"names":[],"version":3,"file":"index.cjs.map"}