You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

142 lines
3.8 KiB

/*!
* lib/remote-importer/local-indexer-wrapper.js
* Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved.
*/
'use strict'
const bitcoin = require('bitcoinjs-lib')
const Logger = require('../logger')
const network = require('../bitcoin/network')
const activeNet = network.network
const keys = require('../../keys')[network.key]
const RpcClient = require('../indexer-rpc/rpc-client')
const Wrapper = require('./wrapper')
/**
* Wrapper for a local indexer
* Currently supports indexers
* providing a RPC API compliant
* with a subset of the electrum protocol
*/
class LocalIndexerWrapper extends Wrapper {
/**
* Constructor
*/
constructor() {
super(null, null)
// RPC client
this.client = new RpcClient()
}
/**
* Translate a bitcoin address into a script hash
* (@see https://electrumx.readthedocs.io/en/latest/protocol-basics.html#script-hashes)
* @param {string} address - bitcoin address
* @returns {string} returns the script hash associated to the address
*/
_getScriptHash(address) {
const bScriptPubKey = bitcoin.address.toOutputScript(address, activeNet)
const bScriptHash = bitcoin.crypto.sha256(bScriptPubKey)
return bScriptHash.reverse().toString('hex')
}
/**
* Retrieve information for a given address
* @param {string} address - bitcoin address
* @param {boolean} filterAddr - True if an upper bound should be used
* for #transactions associated to the address, False otherwise
* @returns {Promise} returns an object
* { address: <bitcoin_address>, txids: <txids>, ntx: <total_nb_txs>}
*/
async getAddress(address, filterAddr) {
const ret = {
address: address,
ntx: 0,
txids: []
}
const scriptHash = this._getScriptHash(address)
const results = await this.client.sendRequest(
LocalIndexerWrapper.GET_HISTORY_RPC_CMD,
scriptHash
)
for (let r of results.txs) {
ret.txids.push(r.tx_hash)
ret.ntx++
}
if (filterAddr && ret.ntx > keys.addrFilterThreshold) {
Logger.info(`Importer : Import of ${address} rejected (too many transactions - ${ret.ntx})`)
return {
address: address,
ntx: 0,
txids: []
}
}
return ret
}
/**
* Retrieve information for a given list of addresses
* @param {string} addresses - array of bitcoin addresses
* @param {boolean} filterAddr - True if an upper bound should be used
* for #transactions associated to the address, False otherwise
* @returns {Promise} returns an array of objects
* { address: <bitcoin_address>, txids: <txids>, ntx: <total_nb_txs>}
*/
async getAddresses(addresses, filterAddr) {
const ret = {}
// Build an array of script hashes
const scriptHashes = addresses.map(a => this._getScriptHash(a))
// Build an array of commands
const commands = scriptHashes.map(s => {
return {
method: LocalIndexerWrapper.GET_HISTORY_RPC_CMD,
params: [s]
}
})
// Send the requests
const results = (keys.indexer.localIndexer.batchRequests == 'active')
? await this.client.sendBatch(commands)
: await this.client.sendRequests(commands)
for (let r of results) {
const addr = addresses[r.idxAddr]
const txids = r.txs.map(t => t.tx_hash)
ret[addr] = {
address: addr,
ntx: txids.length,
txids: txids
}
}
const aRet = Object.values(ret)
for (let i in aRet) {
if (filterAddr && aRet[i].ntx > keys.addrFilterThreshold) {
Logger.info(`Importer : Import of ${aRet[i].address} rejected (too many transactions - ${aRet[i].ntx})`)
aRet.splice(i, 1)
}
}
return aRet
}
}
/**
* Get history RPC command (Electrum protocol)
*/
LocalIndexerWrapper.GET_HISTORY_RPC_CMD = 'blockchain.scripthash.get_history'
module.exports = LocalIndexerWrapper