Refactored transaction handling.

This commit is contained in:
softsimon
2020-12-21 23:08:34 +07:00
parent 5dbf6789a7
commit ecc0f316cc
12 changed files with 331 additions and 145 deletions

View File

@@ -1,16 +1,17 @@
import { MempoolInfo, Transaction, Block, MempoolEntries, MempoolEntry } from '../../interfaces';
import { MempoolInfo, Transaction, Block, MempoolEntries, MempoolEntry, Address } from '../../interfaces';
export interface AbstractBitcoinApi {
getMempoolInfo(): Promise<MempoolInfo>;
getRawMempool(): Promise<Transaction['txid'][]>;
getRawTransaction(txId: string): Promise<Transaction>;
getBlockHeightTip(): Promise<number>;
getTxIdsForBlock(hash: string): Promise<string[]>;
getBlockHash(height: number): Promise<string>;
getBlock(hash: string): Promise<Block>;
getMempoolEntry(txid: string): Promise<MempoolEntry>;
$getMempoolInfo(): Promise<MempoolInfo>;
$getRawMempool(): Promise<Transaction['txid'][]>;
$getRawTransaction(txId: string): Promise<Transaction>;
$getBlockHeightTip(): Promise<number>;
$getTxIdsForBlock(hash: string): Promise<string[]>;
$getBlockHash(height: number): Promise<string>;
$getBlock(hash: string): Promise<Block>;
$getMempoolEntry(txid: string): Promise<MempoolEntry>;
$getAddress(address: string): Promise<Address>;
// Custom
getRawMempoolVerbose(): Promise<MempoolEntries>;
getRawTransactionBitcond(txId: string): Promise<Transaction>;
$getRawMempoolVerbose(): Promise<MempoolEntries>;
$getRawTransactionBitcond(txId: string): Promise<Transaction>;
}

View File

@@ -1,5 +1,5 @@
import config from '../../config';
import { Transaction, Block, MempoolInfo, RpcBlock, MempoolEntries, MempoolEntry } from '../../interfaces';
import { Transaction, Block, MempoolInfo, RpcBlock, MempoolEntries, MempoolEntry, Address } from '../../interfaces';
import * as bitcoin from '@mempool/bitcoin';
class BitcoindApi {
@@ -15,23 +15,23 @@ class BitcoindApi {
});
}
getMempoolInfo(): Promise<MempoolInfo> {
$getMempoolInfo(): Promise<MempoolInfo> {
return this.bitcoindClient.getMempoolInfo();
}
getRawMempool(): Promise<Transaction['txid'][]> {
$getRawMempool(): Promise<Transaction['txid'][]> {
return this.bitcoindClient.getRawMemPool();
}
getRawMempoolVerbose(): Promise<MempoolEntries> {
$getRawMempoolVerbose(): Promise<MempoolEntries> {
return this.bitcoindClient.getRawMemPool(true);
}
getMempoolEntry(txid: string): Promise<MempoolEntry> {
return this.bitcoindClient.getMempoolEntry(txid,);
$getMempoolEntry(txid: string): Promise<MempoolEntry> {
return this.bitcoindClient.getMempoolEntry(txid);
}
getRawTransaction(txId: string): Promise<Transaction> {
$getRawTransaction(txId: string): Promise<Transaction> {
return this.bitcoindClient.getRawTransaction(txId, true)
.then((transaction: Transaction) => {
transaction.vout.forEach((vout) => vout.value = vout.value * 100000000);
@@ -39,23 +39,23 @@ class BitcoindApi {
});
}
getBlockHeightTip(): Promise<number> {
$getBlockHeightTip(): Promise<number> {
return this.bitcoindClient.getChainTips()
.then((result) => result[0].height);
}
getTxIdsForBlock(hash: string): Promise<string[]> {
$getTxIdsForBlock(hash: string): Promise<string[]> {
return this.bitcoindClient.getBlock(hash, 1)
.then((rpcBlock: RpcBlock) => {
return rpcBlock.tx;
});
}
getBlockHash(height: number): Promise<string> {
return this.bitcoindClient.getBlockHash(height)
$getBlockHash(height: number): Promise<string> {
return this.bitcoindClient.getBlockHash(height);
}
getBlock(hash: string): Promise<Block> {
$getBlock(hash: string): Promise<Block> {
return this.bitcoindClient.getBlock(hash)
.then((rpcBlock: RpcBlock) => {
return {
@@ -75,7 +75,11 @@ class BitcoindApi {
});
}
getRawTransactionBitcond(txId: string): Promise<Transaction> {
$getRawTransactionBitcond(txId: string): Promise<Transaction> {
throw new Error('Method not implemented.');
}
$getAddress(address: string): Promise<Address> {
throw new Error('Method not implemented.');
}
}

View File

@@ -1,9 +1,10 @@
import config from '../../config';
import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory';
import { Transaction, Block, MempoolInfo, RpcBlock, MempoolEntries, MempoolEntry } from '../../interfaces';
import { Transaction, Block, MempoolInfo, RpcBlock, MempoolEntries, MempoolEntry, Address } from '../../interfaces';
import * as bitcoin from '@mempool/bitcoin';
import * as ElectrumClient from '@codewarriorr/electrum-client-js';
import logger from '../../logger';
import transactionUtils from '../transaction-utils';
class BitcoindElectrsApi implements AbstractBitcoinApi {
bitcoindClient: any;
@@ -27,64 +28,64 @@ class BitcoindElectrsApi implements AbstractBitcoinApi {
this.electrumClient.connect(
'electrum-client-js',
'1.4'
)
);
}
getMempoolInfo(): Promise<MempoolInfo> {
$getMempoolInfo(): Promise<MempoolInfo> {
return this.bitcoindClient.getMempoolInfo();
}
getRawMempool(): Promise<Transaction['txid'][]> {
$getRawMempool(): Promise<Transaction['txid'][]> {
return this.bitcoindClient.getRawMemPool();
}
getRawMempoolVerbose(): Promise<MempoolEntries> {
$getRawMempoolVerbose(): Promise<MempoolEntries> {
return this.bitcoindClient.getRawMemPool(true);
}
getMempoolEntry(txid: string): Promise<MempoolEntry> {
return this.bitcoindClient.getMempoolEntry(txid,);
$getMempoolEntry(txid: string): Promise<MempoolEntry> {
return this.bitcoindClient.getMempoolEntry(txid);
}
async getRawTransaction(txId: string): Promise<Transaction> {
async $getRawTransaction(txId: string): Promise<Transaction> {
try {
const transaction: Transaction = await this.electrumClient.blockchain_transaction_get(txId, true);
if (!transaction) {
throw new Error('not found');
throw new Error(txId + ' not found!');
}
transaction.vout.forEach((vout) => vout.value = vout.value * 100000000);
transactionUtils.bitcoindToElectrsTransaction(transaction);
return transaction;
} catch (e) {
logger.debug('getRawTransaction error: ' + (e.message || e));
logger.debug('getRawTransaction error: ' + (e.message || e));
throw new Error(e);
}
}
getRawTransactionBitcond(txId: string): Promise<Transaction> {
$getRawTransactionBitcond(txId: string): Promise<Transaction> {
return this.bitcoindClient.getRawTransaction(txId, true)
.then((transaction: Transaction) => {
transaction.vout.forEach((vout) => vout.value = vout.value * 100000000);
transactionUtils.bitcoindToElectrsTransaction(transaction);
return transaction;
});
}
getBlockHeightTip(): Promise<number> {
$getBlockHeightTip(): Promise<number> {
return this.bitcoindClient.getChainTips()
.then((result) => result[0].height);
}
getTxIdsForBlock(hash: string): Promise<string[]> {
$getTxIdsForBlock(hash: string): Promise<string[]> {
return this.bitcoindClient.getBlock(hash, 1)
.then((rpcBlock: RpcBlock) => {
return rpcBlock.tx;
});
}
getBlockHash(height: number): Promise<string> {
return this.bitcoindClient.getBlockHash(height)
$getBlockHash(height: number): Promise<string> {
return this.bitcoindClient.getBlockHash(height);
}
getBlock(hash: string): Promise<Block> {
$getBlock(hash: string): Promise<Block> {
return this.bitcoindClient.getBlock(hash)
.then((rpcBlock: RpcBlock) => {
return {
@@ -103,6 +104,19 @@ class BitcoindElectrsApi implements AbstractBitcoinApi {
};
});
}
async $getAddress(address: string): Promise<Address> {
try {
const addressInfo: Address = await this.electrumClient.blockchain_scripthash_getBalance(address);
if (!address) {
throw new Error('not found');
}
return addressInfo;
} catch (e) {
logger.debug('getRawTransaction error: ' + (e.message || e));
throw new Error(e);
}
}
}
export default BitcoindElectrsApi;

View File

@@ -1,6 +1,6 @@
import config from '../../config';
import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory';
import { Transaction, Block, MempoolInfo, MempoolEntry, MempoolEntries } from '../../interfaces';
import { Transaction, Block, MempoolInfo, MempoolEntry, MempoolEntries, Address } from '../../interfaces';
import axios from 'axios';
class ElectrsApi implements AbstractBitcoinApi {
@@ -8,7 +8,7 @@ class ElectrsApi implements AbstractBitcoinApi {
constructor() {
}
getMempoolInfo(): Promise<MempoolInfo> {
$getMempoolInfo(): Promise<MempoolInfo> {
return axios.get<any>(config.ELECTRS.REST_API_URL + '/mempool', { timeout: 10000 })
.then((response) => {
return {
@@ -18,45 +18,49 @@ class ElectrsApi implements AbstractBitcoinApi {
});
}
getRawMempool(): Promise<Transaction['txid'][]> {
$getRawMempool(): Promise<Transaction['txid'][]> {
return axios.get<Transaction['txid'][]>(config.ELECTRS.REST_API_URL + '/mempool/txids')
.then((response) => response.data);
}
getRawTransaction(txId: string): Promise<Transaction> {
$getRawTransaction(txId: string): Promise<Transaction> {
return axios.get<Transaction>(config.ELECTRS.REST_API_URL + '/tx/' + txId)
.then((response) => response.data);
}
getBlockHeightTip(): Promise<number> {
$getBlockHeightTip(): Promise<number> {
return axios.get<number>(config.ELECTRS.REST_API_URL + '/blocks/tip/height')
.then((response) => response.data);
}
getTxIdsForBlock(hash: string): Promise<string[]> {
$getTxIdsForBlock(hash: string): Promise<string[]> {
return axios.get<string[]>(config.ELECTRS.REST_API_URL + '/block/' + hash + '/txids')
.then((response) => response.data);
}
getBlockHash(height: number): Promise<string> {
$getBlockHash(height: number): Promise<string> {
return axios.get<string>(config.ELECTRS.REST_API_URL + '/block-height/' + height)
.then((response) => response.data);
}
getBlock(hash: string): Promise<Block> {
$getBlock(hash: string): Promise<Block> {
return axios.get<Block>(config.ELECTRS.REST_API_URL + '/block/' + hash)
.then((response) => response.data);
}
getRawMempoolVerbose(): Promise<MempoolEntries> {
$getRawMempoolVerbose(): Promise<MempoolEntries> {
throw new Error('Method not implemented.');
}
getMempoolEntry(): Promise<MempoolEntry> {
$getMempoolEntry(): Promise<MempoolEntry> {
throw new Error('Method not implemented.');
}
getRawTransactionBitcond(txId: string): Promise<Transaction> {
$getRawTransactionBitcond(txId: string): Promise<Transaction> {
throw new Error('Method not implemented.');
}
$getAddress(address: string): Promise<Address> {
throw new Error('Method not implemented.');
}
}