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.
 
 
 
 
 
 

173 lines
3.6 KiB

/*!
* tracker/block-worker.js
* Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved.
*/
'use strict'
const { isMainThread, parentPort } = require('worker_threads')
const network = require('../lib/bitcoin/network')
const keys = require('../keys')[network.key]
const db = require('../lib/db/mysql-db-wrapper')
const RpcClient = require('../lib/bitcoind-rpc/rpc-client')
const Block = require('./block')
/**
* STATUS
*/
const IDLE = 0
module.exports.IDLE = IDLE
const INITIALIZED = 1
module.exports.INITIALIZED = INITIALIZED
const OUTPUTS_PROCESSED = 2
module.exports.OUTPUTS_PROCESSED = OUTPUTS_PROCESSED
const INPUTS_PROCESSED = 3
module.exports.INPUTS_PROCESSED = INPUTS_PROCESSED
const TXS_CONFIRMED = 4
module.exports.TXS_CONFIRMED = TXS_CONFIRMED
/**
* OPS
*/
const OP_INIT = 0
module.exports.OP_INIT = OP_INIT
const OP_PROCESS_OUTPUTS = 1
module.exports.OP_PROCESS_OUTPUTS = OP_PROCESS_OUTPUTS
const OP_PROCESS_INPUTS = 2
module.exports.OP_PROCESS_INPUTS = OP_PROCESS_INPUTS
const OP_CONFIRM = 3
module.exports.OP_CONFIRM = OP_CONFIRM
const OP_RESET = 4
module.exports.OP_RESET = OP_RESET
/**
* Process message received by the worker
* @param {object} msg - message received by the worker
*/
async function processMessage(msg) {
let res = null
let success = true
try {
switch(msg.op) {
case OP_INIT:
if (status != IDLE)
throw 'Operation not allowed'
res = await initBlock(msg.header)
break
case OP_PROCESS_OUTPUTS:
if (status != INITIALIZED)
throw 'Operation not allowed'
res = await processOutputs()
break
case OP_PROCESS_INPUTS:
if (status != OUTPUTS_PROCESSED)
throw 'Operation not allowed'
res = await processInputs()
break
case OP_CONFIRM:
if (status != INPUTS_PROCESSED)
throw 'Operation not allowed'
res = await confirmTransactions(msg.blockId)
break
case OP_RESET:
res = await reset()
break
default:
throw 'Invalid Operation'
}
} catch (e) {
success = false
res = e
} finally {
parentPort.postMessage({
'op': msg.op,
'status': success,
'res': res
})
}
}
/**
* Initialize the block
* @param {object} header - block header
*/
async function initBlock(header) {
status = INITIALIZED
const hex = await rpcClient.getblock(header.hash, false)
block = new Block(hex, header)
return true
}
/**
* Process the transactions outputs
*/
async function processOutputs() {
status = OUTPUTS_PROCESSED
txsForBroadcast = await block.processOutputs()
return true
}
/**
* Process the transactions inputs
*/
async function processInputs() {
status = INPUTS_PROCESSED
const txs = await block.processInputs()
txsForBroadcast = txsForBroadcast.concat(txs)
return true
}
/**
* Confirm the transactions
* @param {integer} blockId - id of the block in db
*/
async function confirmTransactions(blockId) {
status = TXS_CONFIRMED
const aTxsForBroadcast = [...new Set(txsForBroadcast)]
await block.confirmTransactions(aTxsForBroadcast, blockId)
return aTxsForBroadcast
}
/**
* Reset
*/
function reset() {
status = IDLE
block = null
txsForBroadcast = []
return true
}
/**
* MAIN
*/
const rpcClient = new RpcClient()
let block = null
let txsForBroadcast = []
let status = IDLE
if (!isMainThread) {
db.connect({
connectionLimit: keys.db.connectionLimitTracker,
acquireTimeout: keys.db.acquireTimeout,
host: keys.db.host,
user: keys.db.user,
password: keys.db.pass,
database: keys.db.database
})
reset()
parentPort.on('message', processMessage)
}