Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Self-hosted Bitcoin BSV transaction storage and UTXO indexer for developers.
LICENSE: MIT
In order for Bitcoin SV apps to scale efficiently as traditional web services, apps must communicate directly with each other where possible and not rely on extra intermediaries.
Not all Bitcoin miners or transaction processors will maintain a full transaction index for public consumption. Some will instead opt to run so called "transaction pruning" nodes and instead specialize in other ways than offering data storage and indexing services.
TXQ decouples your application from miners and other Bitcoin service providers.
It's easy and extremely cost effective for services to simply index their own Bitcoin transactions and have the "single source of truth" be ready at hand and according to their backup needs.
TXQ makes it easy for developers to keep their entire application transaction history in their direct control or even on premise. At the same time, transaction sending is now "fire and forget" annd synchronization with miners happens automatically via Merchant API.
Requirements:
Install global TypeScript and TypeScript Node
npm install -g typescript ts-node
Setup and Run
Copy .env.example
to .env
for productionn environment. See database instructions below.
Install deps:
npm install
Developer testing:
npm run start-dev
Production build:
npm run build
Production run:
node ./dist/bootstrap/index.js
Testing:
jest
Initial Schema:
src/database/202006210000-init-schema.sql
Migrations:
See cfg/index.ts
for available options.
{
// ...
queue: {
// Max number of concurrent requests to sync tx status from merchantapi
taskRequestConcurrency: process.env.MERCHANT_API_CONCURRENCY ? parseInt(process.env.MERCHANT_API_CONCURRENCY) : 3,
abandonedSyncTaskRescanSeconds: 60, // How many seconds to rescan for missed tasks
syncBackoff: {
// 'full' or 'none'
jitter: process.env.SYNC_JITTER ? process.env.SYNC_JITTER : 'none',
// Exponential back off multiple
timeMultiple: process.env.SYNC_BACKOFF_MULTIPLE ? parseInt(process.env.SYNC_BACKOFF_MULTIPLE) : 2,
// Initial start delay before first re-check
startingDelay: process.env.SYNC_START_DELAY ? parseInt(process.env.SYNC_START_DELAY) : 1000 * 60,
// Max back off time. 20 Minutes is max
maxDelay: process.env.SYNC_MAX_DELAY ? parseInt(process.env.SYNC_MAX_DELAY) : 1000 * 60 * 20,
// Max attempts before being put into 'dlq'
numOfAttempts: process.env.SYNC_MAX_ATTEMPTS ? parseInt(process.env.SYNC_MAX_ATTEMPTS) : 20
}
},
enableUpdateLogging: true, // Whether to log every update entity to the database
merchantapi: {
sendPolicy: 'ALL_FIRST_PRIORITY_SUCCESS', // 'SERIAL_BACKUP' | 'ALL_FIRST_PRIORITY_SUCCESS';
statusPolicy: 'SERIAL_BACKUP', // 'SERIAL_BACKUP'
enableResponseLogging: true, // Whether to log every request and response from merchantapi's to the database
enableProxy: true, // Exposes /merchantapi/<miner name>/mapi/tx endpoints...
endpoints: [
{
name: 'matterpool.io',
url: 'https://merchantapi.matterpool.io',
headers: {
}
},
{
name: 'taal.com',
url: 'https://merchantapi.taal.com',
headers: {
}
},
{
name: 'mempool.io',
url: 'https://www.ddpurse.com/openapi',
headers: {
token: "561b756d12572020ea9a104c3441b71790acbbce95a6ddbf7e0630971af9424b"
}
},
]
},
//...
Enterprise ready
Relational Database (Postgres)
jsonb
Easy to integrate API and Real-time Sockets
Open Source and Schema
Enterprise and Paid Hosting
TL;DR: Sending transactions is now "fire and forget". TLQ is a concurrent work queue that synchronizes transaction status with miners automatically — so you, the developer, do not have to worry it. TXQ complements your infrastructure and gives you full control over your apps slice of the BSV blockchain universe. Out-of-the-box you have your own TX and UTXO indexer for addresses, scripthashes, outpoints and spend indexes. Transaction processors (miners) now can focus on building and time-stamping blocks and leave it to apps to backup and own their own transaction data.
Up until now, Bitcoin SV "apps" relied on miners and blockchain cloudhosting services to get UTXO and transaction data. TXQ means app developers do not need to rely on 3rd parties for UTXO and transaction data — as long as all transactions of interest are saved to TXQ. That's it.
In order for Bitcoin SV applications to be able to scale as efficiently as traditional web services, the applications must be able to interoperate peer-to-peer and not rely on extra intermediaries.
To scale, Bitcoin applications must act more like peers and use the rawtx
format as the application data medium of exchange. Each service provider will maintain a copy of the rawtx
for all transactions in traditional storage and backed up to their policy.
TXQ abstracts the transaction settlement process with miners so developers focus on building and integrating your applications.
Provide your application and services with a consistent picture of it's "Bitcoin State" without relying on 3rd parties for lookups and indexing.
Reliably broadcast transactions to a set of miners to get them reliably settled. Queue configuration options allow customizing the concurrency limit, exponential back off, and other behaviors.
All Merchant API requests are logged to the database and also streamed in real-time to the SSE event interface.
TXQ automatically stores and indexes UTXOs and transactions without relying on miners and cloud providers. Your businness always has transaction history and UTXOs ready-at-hand and can easily scale with no miner or vendor lock-in.
Easily connect TXQ with your other services via SSE sockets for subscribing to new transactions and events in real-time.
Try it at: https://txq.matterpool.io
Example:
https://txq.matterpool.io/api/v1/tx/dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293?pretty=1
Save a transaction and/or txid, attaching optional metadata. The txid must match the rawtx's txid.
POST /api/v1/tx
//Request:
// Note: you can set multiple transactions in a single call
{
"channel": null, // Optional channel queue name
"set":{
"94aaa2f1a7e0042ba19fbb8bb87be87ecb8d025aa88844b8bea85eb7cb2d678d":{
"rawtx": "0100000002af6d598d7ee12bec6b20e460e97b99d048ea6c73bab291827e42dd99ba34704d020000006a47304402203b9b01392167dfd15259d5f7782521852809a384b30f44b8009fa516a4e76fe0022006cbae89516bdb5a3c135aefaf29cdfa7545b5f2ea9d6394e8689735a040d575412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffffaf6d598d7ee12bec6b20e460e97b99d048ea6c73bab291827e42dd99ba34704d010000006b483045022100bb1c98453c2ea76eee6ee17a1961a9b8b418d1a0a0ee4b1c8b19d7f45d4bba9a02201a7d259ff8203c357ba5dcdb5141f9fd2b35f167429e556c6ea90cf8d534928a412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff02000000000000000019006a026d0213706f73746420746f206d6465646464646d6f21089d0000000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"metadata":{
"title":"some title",
"content":"any content",
"url":"https://www.nintendo.com",
"image":"",
"description":"DOOOOOO"
},
"tags":[ "bitcoin", "bsv"]
}
}
}
// Response:
// Note: you can set multiple transactions in a single call
{
"status": 200,
"errors": [],
"result": [
"94aaa2f1a7e0042ba19fbb8bb87be87ecb8d025aa88844b8bea85eb7cb2d678d"
]
}
GET /api/v1/tx/94aaa2f1a7e0042ba19fbb8bb87be87ecb8d025aa88844b8bea85eb7cb2d678d?pretty
Params:
Retrieve the transaction status and metadata for the null
default channel. complete
will be set to true
when the transaction is confirmed.
// Response:
{
"status": 200,
"errors": [],
"result": {
"txid": "94aaa2f1a7e0042ba19fbb8bb87be87ecb8d025aa88844b8bea85eb7cb2d678d",
"rawtx": "0100000002af6d598d7ee12bec6b20e460e97b99d048ea6c73bab291827e42dd99ba34704d020000006a47304402203b9b01392167dfd15259d5f7782521852809a384b30f44b8009fa516a4e76fe0022006cbae89516bdb5a3c135aefaf29cdfa7545b5f2ea9d6394e8689735a040d575412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffffaf6d598d7ee12bec6b20e460e97b99d048ea6c73bab291827e42dd99ba34704d010000006b483045022100bb1c98453c2ea76eee6ee17a1961a9b8b418d1a0a0ee4b1c8b19d7f45d4bba9a02201a7d259ff8203c357ba5dcdb5141f9fd2b35f167429e556c6ea90cf8d534928a412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff02000000000000000019006a026d0213706f73746420746f206d6465646464646d6f21089d0000000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"h": "00000000000000000324d7ada9f810f08b254dffce4786bc4cf30374ee23a4db",
"i": 640259,
"send": null,
"status": {
"valid": true,
"payload": {
"minerId": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash": "00000000000000000324d7ada9f810f08b254dffce4786bc4cf30374ee23a4db",
"timestamp": "2020-06-21T01:02:42.952Z",
"apiVersion": "0.1.0",
"blockHeight": 640259,
"returnResult": "success",
"confirmations": 25,
"resultDescription": "",
"txSecondMempoolExpiry": 0
},
"encoding": "UTF-8",
"mimetype": "application/json",
"publicKey": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature": "30440220281148a447cf041fcebfeba8bba0ad022299d321a6dc7641b3ad54239f505eaf02207cffd042ebb18285e7160429fe51fb9bcac005b04469877248afdc509e41de61"
},
"completed": true,
"updated_at": 1592765256,
"created_at": 1592697895,
"channel": "",
"id": 43, // stream message identifier
"metadata":{
"title":"some title",
"content":"any content",
"url":"https://www.nintendo.com",
"image":"",
"description":"DOOOOOO"
},
"tags":[ "bitcoin", "bsv"]
"extracted": {}
}
}
GET /api/v1/tx/94aaa2f1a7e0042ba19fbb8bb87be87ecb8d025aa88844b8bea85eb7cb2d678d/channel/somechannelchannel?pretty
Params:
Retrieve the transaction status and metadata for the somechannelchannel
default channel. complete
will be set to true
when the transaction is confirmed.
// Response:
{
"status": 200,
"errors": [],
"result": {
"txid": "94aaa2f1a7e0042ba19fbb8bb87be87ecb8d025aa88844b8bea85eb7cb2d678d",
"rawtx": "0100000002af6d598d7ee12bec6b20e460e97b99d048ea6c73bab291827e42dd99ba34704d020000006a47304402203b9b01392167dfd15259d5f7782521852809a384b30f44b8009fa516a4e76fe0022006cbae89516bdb5a3c135aefaf29cdfa7545b5f2ea9d6394e8689735a040d575412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffffaf6d598d7ee12bec6b20e460e97b99d048ea6c73bab291827e42dd99ba34704d010000006b483045022100bb1c98453c2ea76eee6ee17a1961a9b8b418d1a0a0ee4b1c8b19d7f45d4bba9a02201a7d259ff8203c357ba5dcdb5141f9fd2b35f167429e556c6ea90cf8d534928a412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff02000000000000000019006a026d0213706f73746420746f206d6465646464646d6f21089d0000000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"h": "00000000000000000324d7ada9f810f08b254dffce4786bc4cf30374ee23a4db",
"i": 640259,
"send": null,
"status": {
"valid": true,
"payload": {
"minerId": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash": "00000000000000000324d7ada9f810f08b254dffce4786bc4cf30374ee23a4db",
"timestamp": "2020-06-21T01:02:42.952Z",
"apiVersion": "0.1.0",
"blockHeight": 640259,
"returnResult": "success",
"confirmations": 25,
"resultDescription": "",
"txSecondMempoolExpiry": 0
},
"encoding": "UTF-8",
"mimetype": "application/json",
"publicKey": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature": "30440220281148a447cf041fcebfeba8bba0ad022299d321a6dc7641b3ad54239f505eaf02207cffd042ebb18285e7160429fe51fb9bcac005b04469877248afdc509e41de61"
},
"id": 43,
"completed": true,
"updated_at": 1592765256,
"created_at": 1592697895,
"channel": "",
"metadata":{
"title":"some title",
"content":"any content",
"url":"https://www.nintendo.com",
"image":"",
"description":"DOOOOOO"
},
"tags":[ "bitcoin", "bsv"]
"extracted": {}
}
}
GET /api/v1/channel?pretty=1&rawtx=1&id=0&limit=1000
Params:
Retrieve the transactions from most recently added in the default null
channel queue
// Response:
{
"status": 200,
"errors": [],
"result": [
{
"txid": "4d7034ba99dd427e8291b2ba736cea48d0997be960e4206bec2be17e8d596daf",
"i": 640259,
"h": "00000000000000000324d7ada9f810f08b254dffce4786bc4cf30374ee23a4db",
"rawtx": "0100000001f743dd880dde880b0e5baf3403352c25005ad94fcafc79abc35d2ee52a212bd4020000006b483045022100aff74f1335bbc691cc62c7405a77c09744626363397dc47cfe97e235e5a0143102203357855791f03b4ae3332808f9964af8f24e0b63e7bd32f6788f77e2d2da7b50412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff03000000000000000019006a026d0213706f73746420746f206d6465646464646d6f2168100000000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288acc58d0000000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"send": null,
"status": {
"valid": true,
"payload": {
"minerId": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash": "00000000000000000324d7ada9f810f08b254dffce4786bc4cf30374ee23a4db",
"timestamp": "2020-06-21T01:02:41.139Z",
"apiVersion": "0.1.0",
"blockHeight": 640259,
"returnResult": "success",
"confirmations": 25,
"resultDescription": "",
"txSecondMempoolExpiry": 0
},
"encoding": "UTF-8",
"mimetype": "application/json",
"publicKey": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature": "304402204e4d4d8e03182a80608f7a583db008a783d40895a67339e3576b9abf09e6992c022047b5eb1de9103ed628f4accfce632755921527f3306831d346f0936c5fcd6026"
},
"completed": true,
"updated_at": 1592701751,
"created_at": 1592701361,
"channel": "",
"metadata": {
"url": "url",
"image": "adfsfsdfsdfdf",
"title": "abc",
"content": "content123",
"description": "DOOOOOO"
},
"tags": [
"ckitty",
"cat"
],
"extracted": {}
}
]
}
GET /api/v1/channel/:channel?pretty=1&rawtx=1&id=0&limit=1000
Params:
Retrieve the transactions from most recently added in the default :channel
channel queue
// Response:
{
"status": 200,
"errors": [],
"result": [
{
"txid": "dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293",
"i": 640464,
"h": "000000000000000000e3564e4a8d9be13fb24cb21d546cb999d514c650c3b2dc",
"rawtx": "0200000003c3be676ae826227bcff47e605bdffff85c4aa42e3c868e4dfad9a97e2244aef5000000006a4730440220692e3f1fb99e26e494c8e446621584564e67e1388b06e7be769f3adde6b5c3c60220148e97efbc41dda03d80de2249be68c332b12ff7148e61847a72e93eee2e06864121037e7bcc2cdc24646fd8e320c74f156367027c1b67564c0dee420262eca71fca56feffffffd8fa56930181c8431c4d7d503d8b5d5948f22e4c9311d3fb19847b2318dd227d010000006b483045022100f5b8bf9905e5ec051573fd522c522295a5944e460255869dba427f64e6a094d3022032cbb4814b62daf1647570a35903f211143e3d82a8446986761612910936b95c4121037e7bcc2cdc24646fd8e320c74f156367027c1b67564c0dee420262eca71fca56feffffff1c2067e5d0212cc015e3ece148c218008a44eff32a5f6eb4acc238477d9e034a010000006a47304402205d525e4846f964c69c8d830fd9a1823e78ba3085d95405071e822136576326a40220676a18f3e0eb77ff1e9a2b91d54a61cc9642745e2dd55dd0564122010db2266f4121037e7bcc2cdc24646fd8e320c74f156367027c1b67564c0dee420262eca71fca56feffffff022f130873070000001976a914a1f93cb1d124a82f8f86b06ef97a4fd6d77c04e288aca6386727000000001976a9140ca78f443c75e178674bd40337e9fe7f8745cbc088ac9f860100",
"send": null,
"status": {
"valid": true,
"payload": {
"minerId": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash": "000000000000000000e3564e4a8d9be13fb24cb21d546cb999d514c650c3b2dc",
"timestamp": "2020-06-22T10:05:15.165Z",
"apiVersion": "0.1.0",
"blockHeight": 640464,
"returnResult": "success",
"confirmations": 1,
"resultDescription": "",
"txSecondMempoolExpiry": 0
},
"encoding": "UTF-8",
"mimetype": "application/json",
"publicKey": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature": "304402201029251d228486f7c2b100fb1fd519053b71480c15332d55e694ebb60baa906d02205a61406d5b4c55864381a4053484739fb01ce36f49179463731be442048863b1"
},
"completed": true,
"updated_at": 1592820315,
"created_at": 1592820315,
"channel": "somechannelchannel",
"metadata": {
"url": "https://www.nintendo.com",
"image": "",
"title": "some title",
"content": "any content",
"description": "DOOOOOO"
},
"tags": [
"bitcoin",
"bsv"
],
"extracted": {}
}
]
}
GET /api/v1/txout/txid/:txid/:index?pretty=1
Params:
Retrieve spent status of a txoutput (txid + index)
{
"status": 200,
"errors": [],
"result": {
"txid": "dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293",
"index": 0,
"script": "76a914a1f93cb1d124a82f8f86b06ef97a4fd6d77c04e288ac",
"address": "1FmSNBWW2m6d6FDUWxDjaJo9jhNAs9Pekr",
"scripthash": "ee7beac2fcc315b37f190530d743769f255b1d413edd6e51bbc003022753f909",
"satoshis": 31994680111,
"is_receive": true,
"spend_txid": null,
"spend_index": null
}
}
GET /api/v1/txout/address/:address?pretty=1&offset=0&limit=1000
Params:
Retrieve outputs involving address. Note: receives are tracked only for now.
{
"status": 200,
"errors": [],
"result": [
{
"txid": "dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293",
"index": 0,
"script": "76a914a1f93cb1d124a82f8f86b06ef97a4fd6d77c04e288ac",
"address": "1FmSNBWW2m6d6FDUWxDjaJo9jhNAs9Pekr",
"scripthash": "ee7beac2fcc315b37f190530d743769f255b1d413edd6e51bbc003022753f909",
"satoshis": 31994680111,
"is_receive": true,
"spend_txid": null,
"spend_index": null
}
]
}
GET /api/v1/txout/address/:address/utxo?pretty=1&offset=0&limit=1000
Params:
Retrieve outputs involving address. Note: receives are tracked only for now.
{
"status": 200,
"errors": [],
"result": [
{
"txid": "dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293",
"vout": 0,
"outputIndex": 0,
"value": 31994680111,
"satoshis": 31994680111,
"address": "1FmSNBWW2m6d6FDUWxDjaJo9jhNAs9Pekr",
"scripthash": "ee7beac2fcc315b37f190530d743769f255b1d413edd6e51bbc003022753f909"
}
]
}
GET /api/v1/txout/scripthash/:scripthash?pretty=1&offset=0&limit=1000
Params:
Retrieve outputs involving scripthash. Note: receives are tracked only for now.
{
"status": 200,
"errors": [],
"result": [
{
"txid": "dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293",
"index": 0,
"script": "76a914a1f93cb1d124a82f8f86b06ef97a4fd6d77c04e288ac",
"address": "1FmSNBWW2m6d6FDUWxDjaJo9jhNAs9Pekr",
"scripthash": "ee7beac2fcc315b37f190530d743769f255b1d413edd6e51bbc003022753f909",
"satoshis": 31994680111,
"is_receive": true,
"spend_txid": null,
"spend_index": null
}
]
}
GET /api/v1/txout/scripthash/:scripthash/utxo?pretty=1&offset=0&limit=1000
Params:
Retrieve outputs involving scripthash. Note: receives are tracked only for now.
{
"status": 200,
"errors": [],
"result": [
{
"txid": "dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293",
"vout": 0,
"outputIndex": 0,
"value": 31994680111,
"satoshis": 31994680111,
"address": "1FmSNBWW2m6d6FDUWxDjaJo9jhNAs9Pekr",
"scripthash": "ee7beac2fcc315b37f190530d743769f255b1d413edd6e51bbc003022753f909"
}
]
}
GET /api/v1/queue/stats
Retrieve queue settings and general stats.
{
"status": 200,
"errors": [],
"result": {
"config": {
"concurrency": 3,
"maxDelay": 600000,
"numOfAttempts": 20,
"startingDelay": 60000,
"jitter": "none",
"timeMultiple": 2,
"checkPendingTimeSec": 60
},
"stats": {
"tasks_pending": 0,
"tasks_enq": 0,
"tasks_dup": 0,
"tasks_expired": 0,
"tasks_completed": 0
}
}
}
GET /api/v1/queue/dlq
Retrieve any transaction that were unable to be synced (ie: completed: false
) after the max numOfAttempts
was reached.
All transactions expired get tagged in the default dead-letter queue called dlq
A transaction that is expired, will not be retried unless it is forced to resync
and start the retry again.
{
"status": 200,
"errors": [],
"result": [ 'dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293' ]
}
POST /api/v1/tx/dc7bed6c302c08b7bafd94bfb1086883a134861fe9f212fc8052fcaadcde2293/resync
Use this method to restart any transactions found in the dead-letter queue (dlq).
Sets tx.completed = false
and resets sync = 1
(pending) and kick starts the sync of the send and status of transaction.
{
"status": 200,
"errors": [],
"result": {} // Success is empty
}
Retrieves the txids in the various sync states:
GET /api/v1/queue/sync/success?offset=0&limit=1000&pretty
GET /api/v1/queue/sync/failure?offset=0&limit=1000&pretty
GET /api/v1/queue/sync/none?offset=0&limit=1000&pretty
GET /api/v1/queue/sync/pending?offset=0&limit=1000&pretty
Params:
Retrieve pending txid's that are either success
, failure
, pending
, or none
{{
"status":200,
"errors":[
],
"result":[
"663ee4c9a17070ee5e91eee7f863eaa92ad6ff3144aab94248d4e3ae7380244d",
"a59c5fc76654390239dcb573aee752ad6f2f40ea0e238eac95942ee87f2b9043",
"60fa2f8f144ca71e7f573681940f3fcb63125c4d52d12a647e04ff8b408a16ba",
"3af19895c4a40b8bb49c5623609099068777a2f4451d5a4186105e2fa2e4c27b"
]
}
Use EventSource to reliably receive updates.
The EventSource
automatically handles sending Last-EventId
as a header when the stream reconnects so you will always get any missed updates.
Example streams:
Stream all newly created inserts for the default queue channel
GET /sse/channel/inserts
(SSE)
Example: Inserts
id: -1
data: ["connected"]
id: 101
data: {
"eventType":"newtx",
"entity":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"rawtx":"01000000017708156b6e84cfc73d0d2c549e3e5e3ca9b9886df57ebc1ffae45de1c0d40025010000006b483045022100ab349f73f2334a2f72d68eeb45f2ac6bcfb6c87a00985ae72f43164fdec4b14502204734294f0d403d03f601f1ccc7cf1156701bea371080fc059700957a52846234412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff02000000000000000022006a026d021c706f737420746f6420646d64653364646464646464646564646d6f211f5d0400000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"h":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"i":640721,
"send":{
"payload":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"timestamp":"2020-06-24T03:48:46.740Z",
"apiVersion":"0.1.0",
"returnResult":"success",
"resultDescription":"",
"txSecondMempoolExpiry":0,
"currentHighestBlockHash":"000000000000000003e4685f4a5b4ad32f66f6fde535679138bf9eaa760999cb",
"currentHighestBlockHeight":640720
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3045022100c505903f06b0a944c93b04b10161755e40d4a8e0b95287b35ca8a07dade040d4022026bb44dcef2434de20a2ec0c8ee5591becb92a7628b68872c28e572f371ceefa"
},
"status":{
"valid":true,
"payload":{
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"timestamp":"2020-06-24T03:50:45.083Z",
"apiVersion":"0.1.0",
"blockHeight":640721,
"returnResult":"success",
"confirmations":1,
"resultDescription":"",
"txSecondMempoolExpiry":0
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3044022038dc38e06d66027cce75aef000a581abe92c97ad9240e31f7af043f7dafd7eb50220783fdf925c8ae7f69ef3a0fa81ed10515f70cd265b65b6554252218ea73ec11d"
},
"completed":true,
"updated_at":1592971756,
"created_at":1592970930,
"id":226,
"channel":"bab3",
"metadata":{
"url":"https://www.nintendo.com",
"image":"",
"title":"some title",
"content":"any content",
"description":"DOOOOOO"
},
"tags":[
"bitcoin",
"bsv"
],
"extracted":{
}
}
}
Stream all newly created inserts for the provided custom queue channel
GET /sse/channel/inserts/:channelName
(SSE)
Example: Inserts (with Channel)
id: -1
data: ["connected"]
id: 101
data: {
"eventType":"newtx",
"entity":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"rawtx":"01000000017708156b6e84cfc73d0d2c549e3e5e3ca9b9886df57ebc1ffae45de1c0d40025010000006b483045022100ab349f73f2334a2f72d68eeb45f2ac6bcfb6c87a00985ae72f43164fdec4b14502204734294f0d403d03f601f1ccc7cf1156701bea371080fc059700957a52846234412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff02000000000000000022006a026d021c706f737420746f6420646d64653364646464646464646564646d6f211f5d0400000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"h":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"i":640721,
"send":{
"payload":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"timestamp":"2020-06-24T03:48:46.740Z",
"apiVersion":"0.1.0",
"returnResult":"success",
"resultDescription":"",
"txSecondMempoolExpiry":0,
"currentHighestBlockHash":"000000000000000003e4685f4a5b4ad32f66f6fde535679138bf9eaa760999cb",
"currentHighestBlockHeight":640720
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3045022100c505903f06b0a944c93b04b10161755e40d4a8e0b95287b35ca8a07dade040d4022026bb44dcef2434de20a2ec0c8ee5591becb92a7628b68872c28e572f371ceefa"
},
"status":{
"valid":true,
"payload":{
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"timestamp":"2020-06-24T03:50:45.083Z",
"apiVersion":"0.1.0",
"blockHeight":640721,
"returnResult":"success",
"confirmations":1,
"resultDescription":"",
"txSecondMempoolExpiry":0
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3044022038dc38e06d66027cce75aef000a581abe92c97ad9240e31f7af043f7dafd7eb50220783fdf925c8ae7f69ef3a0fa81ed10515f70cd265b65b6554252218ea73ec11d"
},
"completed":true,
"updated_at":1592971756,
"created_at":1592970930,
"id":226,
"channel":"someChannelName",
"metadata":{
"url":"https://www.nintendo.com",
"image":"",
"title":"some title",
"content":"any content",
"description":"DOOOOOO"
},
"tags":[
"bitcoin",
"bsv"
],
"extracted":{
}
}
}
Stream all newly created inserts and updated transactions for the default queue channel
GET /sse/channel/updates
(SSE)
Example: Updates
id: -1
data: ["connected"]
id: 101
data: {
"eventType":"newtx",
"entity":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"rawtx":"01000000017708156b6e84cfc73d0d2c549e3e5e3ca9b9886df57ebc1ffae45de1c0d40025010000006b483045022100ab349f73f2334a2f72d68eeb45f2ac6bcfb6c87a00985ae72f43164fdec4b14502204734294f0d403d03f601f1ccc7cf1156701bea371080fc059700957a52846234412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff02000000000000000022006a026d021c706f737420746f6420646d64653364646464646464646564646d6f211f5d0400000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"h":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"i":640721,
"send":{
"payload":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"timestamp":"2020-06-24T03:48:46.740Z",
"apiVersion":"0.1.0",
"returnResult":"success",
"resultDescription":"",
"txSecondMempoolExpiry":0,
"currentHighestBlockHash":"000000000000000003e4685f4a5b4ad32f66f6fde535679138bf9eaa760999cb",
"currentHighestBlockHeight":640720
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3045022100c505903f06b0a944c93b04b10161755e40d4a8e0b95287b35ca8a07dade040d4022026bb44dcef2434de20a2ec0c8ee5591becb92a7628b68872c28e572f371ceefa"
},
"status":{
"valid":true,
"payload":{
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"timestamp":"2020-06-24T03:50:45.083Z",
"apiVersion":"0.1.0",
"blockHeight":640721,
"returnResult":"success",
"confirmations":1,
"resultDescription":"",
"txSecondMempoolExpiry":0
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3044022038dc38e06d66027cce75aef000a581abe92c97ad9240e31f7af043f7dafd7eb50220783fdf925c8ae7f69ef3a0fa81ed10515f70cd265b65b6554252218ea73ec11d"
},
"completed":true,
"updated_at":1592971756,
"created_at":1592970930,
"id":226,
"channel":"bab3",
"metadata":{
"url":"https://www.nintendo.com",
"image":"",
"title":"some title",
"content":"any content",
"description":"DOOOOOO"
},
"tags":[
"bitcoin",
"bsv"
],
"extracted":{
}
}
}
Stream all newly created inserts and updated transactions for the provided custom queue channel
GET /sse/channel/updates/:channelName
(SSE)
Example: Updates (with Channel)
Event Types: newtx
, updatetx
id: -1
data: ["connected"]
id: 101
data: {
"eventType":"newtx",
"entity":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"rawtx":"01000000017708156b6e84cfc73d0d2c549e3e5e3ca9b9886df57ebc1ffae45de1c0d40025010000006b483045022100ab349f73f2334a2f72d68eeb45f2ac6bcfb6c87a00985ae72f43164fdec4b14502204734294f0d403d03f601f1ccc7cf1156701bea371080fc059700957a52846234412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff02000000000000000022006a026d021c706f737420746f6420646d64653364646464646464646564646d6f211f5d0400000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000",
"h":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"i":640721,
"send":{
"payload":{
"txid":"f093a1e67bd88cbc8a3fbafb70a8b0bb439b7e5c6b2421ea0c5b49df87e9c2b8",
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"timestamp":"2020-06-24T03:48:46.740Z",
"apiVersion":"0.1.0",
"returnResult":"success",
"resultDescription":"",
"txSecondMempoolExpiry":0,
"currentHighestBlockHash":"000000000000000003e4685f4a5b4ad32f66f6fde535679138bf9eaa760999cb",
"currentHighestBlockHeight":640720
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3045022100c505903f06b0a944c93b04b10161755e40d4a8e0b95287b35ca8a07dade040d4022026bb44dcef2434de20a2ec0c8ee5591becb92a7628b68872c28e572f371ceefa"
},
"status":{
"valid":true,
"payload":{
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"blockHash":"00000000000000000264cab8156c13cc9ea600c7506a4c74640e41c400730711",
"timestamp":"2020-06-24T03:50:45.083Z",
"apiVersion":"0.1.0",
"blockHeight":640721,
"returnResult":"success",
"confirmations":1,
"resultDescription":"",
"txSecondMempoolExpiry":0
},
"encoding":"UTF-8",
"mimetype":"application/json",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"signature":"3044022038dc38e06d66027cce75aef000a581abe92c97ad9240e31f7af043f7dafd7eb50220783fdf925c8ae7f69ef3a0fa81ed10515f70cd265b65b6554252218ea73ec11d"
},
"completed":true,
"updated_at":1592971756,
"created_at":1592970930,
"id":226,
"channel":"someChannelName",
"metadata":{
"url":"https://www.nintendo.com",
"image":"",
"title":"some title",
"content":"any content",
"description":"DOOOOOO"
},
"tags":[
"bitcoin",
"bsv"
],
"extracted":{
}
}
}
Stream all merchant API sends and status updates. This allows you to track confirmation status of tx's.
GET /sse/merchantapilogs
(SSE)
Example: Merchant API Log Streaming
id: -1
data: ["connected"]
id: 171
data: {
"miner": "matterpool.io",
"eventType":"statustx",
"entity":{
"txid":"1b7182a2d6ca5f0caa06ba2ac15ade4e5009e6b8d942ddc958d12b0087a37d34",
"payload":{
"apiVersion":"0.1.0",
"timestamp":"2020-06-24T04:34:45.678Z",
"returnResult":"success",
"resultDescription":"",
"blockHash":"",
"blockHeight":0,
"confirmations":0,
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"txSecondMempoolExpiry":0
},
"signature":"3044022076ec2649ef04d8c3b4780a2d113afe0e42de12451cbeb8fc0138a54ab23b6b62022068f17187888c6c537a71459e75dca5f3eec742691f7f8e9989a9414427d406d4",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"encoding":"UTF-8",
"mimetype":"application/json",
"valid":true
}
}
id: 174
data: {
"miner": "matterpool.io",
"eventType":"pushtx",
"entity":{
"txid":"a64c070d13d22e48f06c5edb692c0498f81d27d97fe6d0e092eebd1cd1063633",
"payload":{
"apiVersion":"0.1.0",
"timestamp":"2020-06-24T04:34:54.001Z",
"txid":"a64c070d13d22e48f06c5edb692c0498f81d27d97fe6d0e092eebd1cd1063633",
"returnResult":"success",
"resultDescription":"",
"minerId":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"currentHighestBlockHash":"000000000000000002f1ac414cf470fa4e1d07794ad15fd75347524119910bc7",
"currentHighestBlockHeight":640730,
"txSecondMempoolExpiry":0
},
"signature":"3045022100ea9b5f918323b95b6bd21b49c5ce6ecfaa2652d3d9ad4d05e42f07b5b3b87144022079bf641752a94b33425ded243459c47209b8a072fac992842c8f1102462400b2",
"publicKey":"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087",
"encoding":"UTF-8",
"mimetype":"application/json"
}
}
Stream all newly created outputs by address
GET /sse/txout/address/:address
(SSE)
Example: Address Stream
id: -1
data: ["connected"]
id: 2
data: {
"entity":{
"txid":"10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2",
"index":1,
"address":"131xY3twRUJ1Y9Z9jJFKGLUa4SAdRJppcW",
"scripthash":"525d063bd0c861fddc4d4881cb495038652bf432c9e2586cc37d49e98a3cc60e",
"script":"76a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac",
"satoshis":284442
},
"eventType":"txout"
}
Stream all newly created outputs by scripthash
GET /sse/txout/scripthash/:scripthash
(SSE)
Example: Scripthash stream
id: -1
data: ["connected"]
id: 2
data: {
"entity":{
"txid":"10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2",
"index":1,
"address":"131xY3twRUJ1Y9Z9jJFKGLUa4SAdRJppcW",
"scripthash":"525d063bd0c861fddc4d4881cb495038652bf432c9e2586cc37d49e98a3cc60e",
"script":"76a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac",
"satoshis":284442
},
"eventType":"txout"
}
Motivation
TXQ exposes a /mapi
endpoint proxy that allows clients to communicate with TXQ directly using the Merchant API.
TXQ automatically saves successfully broadcasted transactions under the default (empty) channel and then retries them as normal until they are settled or expired into the dead-letter queue.
Enable this in the configuration file with (default enabled):
merchantapi: {
...
enableProxy: true, // Exposes Merchant API proxy endpointts
...
}
Resources:
channel
, metadata
, and tags
The Merchant API specification does not accept anything other than rawtx
for POST /mapi/tx
(push tx) therefore we leverage HTTP
headers to allow the client to specify channel
, metadata
, and tags
.
For example, set the following HTTP headers to attach additional information:
channel
: someChannelName
metadata
: {"description": "mydescription", "title": "a cool title"}
tags
: ["animals", "bitcoin"]
Use the first Merchant API endpoint for the request.
All events are logged to the database (enabled by default) under proxypushtx
, proxystatustx
and proxyfeequote
.
Transaction status examples:
GET /mapi/tx/10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2
Push transaction examples:
POST /mapi/tx
Fee quote examples:
GET /mapi/feeQuote
Select a specific miner to send the Merchant API request to. The identifer <miner-name>
must match the name in the configuration file.
All events are logged to the database (enabled by default) under proxypushtx
, proxystatustx
and proxyfeequote
.
Transaction status examples:
GET /merchantapi/taal.com/mapi/tx/10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2
GET /merchantapi/matterpool.io/mapi/tx/10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2
GET /merchantapi/mempool.io/mapi/tx/10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2
Push transaction examples:
POST /merchantapi/taal.com/mapi/tx
POST /merchantapi/matterpool.io/mapi/tx
POST /merchantapi/mempool.io/mapi/tx
Fee quote examples:
GET /merchantapi/taal.com/mapi/feeQuote
GET /merchantapi/matterpool.io/mapi/feeQuote
GET /merchantapi/mempool.io/mapi/feeQuote
Select a specific miner by index (ie: 0 is the first, 1 is the second, etc) to send the Merchant API request to. The identifer <miner-endpoint-index>
must match the name in the configuration file.
All events are logged to the database (enabled by default) under proxypushtx
, proxystatustx
and proxyfeequote
.
Transaction status examples:
GET /merchantapi/0/mapi/tx/10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2
GET /merchantapi/1/mapi/tx/10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2
GET /merchantapi/2/mapi/tx/10ad1739b568d2060831b91771d9b836e0f4efcb113d3a866732bbb9b8ca7ae2
Push transaction examples:
POST /merchantapi/0/mapi/tx
POST /merchantapi/1/mapi/tx
POST /merchantapi/2/mapi/tx
Fee quote examples:
GET /merchantapi/0/mapi/feeQuote
GET /merchantapi/1/mapi/feeQuote
GET /merchantapi/2/mapi/feeQuote
The database chosen is postgres because it provides important features for developers and enterprises:
jsonb
storage and custom indexes
Future work: Abstract away storage and allow developer to choose storage engine.
FAQs
TXQ: Bitcoin Transaction Storage Queue Service
The npm package txq receives a total of 2 weekly downloads. As such, txq popularity was classified as not popular.
We found that txq demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.