Merge node-bitcoin into the project
This commit is contained in:
parent
622a003a2a
commit
e26beee44c
14
backend/package-lock.json
generated
14
backend/package-lock.json
generated
@ -9,7 +9,6 @@
|
|||||||
"version": "2.4.0-dev",
|
"version": "2.4.0-dev",
|
||||||
"license": "GNU Affero General Public License v3.0",
|
"license": "GNU Affero General Public License v3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mempool/bitcoin": "^3.0.3",
|
|
||||||
"@mempool/electrum-client": "^1.1.7",
|
"@mempool/electrum-client": "^1.1.7",
|
||||||
"@types/ws": "8.2.2",
|
"@types/ws": "8.2.2",
|
||||||
"axios": "0.24.0",
|
"axios": "0.24.0",
|
||||||
@ -56,14 +55,6 @@
|
|||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mempool/bitcoin": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@mempool/bitcoin/-/bitcoin-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-10UdbwchnevlebDTN+Xhv75AEhDmTMy9UgWHlqx5MG2mheFG6+eqmtHsdxeYnv3IAtTtlRfA6fY0RbV/x4TNFQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@mempool/electrum-client": {
|
"node_modules/@mempool/electrum-client": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/@mempool/electrum-client/-/electrum-client-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/@mempool/electrum-client/-/electrum-client-1.1.8.tgz",
|
||||||
@ -1515,11 +1506,6 @@
|
|||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@mempool/bitcoin": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@mempool/bitcoin/-/bitcoin-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-10UdbwchnevlebDTN+Xhv75AEhDmTMy9UgWHlqx5MG2mheFG6+eqmtHsdxeYnv3IAtTtlRfA6fY0RbV/x4TNFQ=="
|
|
||||||
},
|
|
||||||
"@mempool/electrum-client": {
|
"@mempool/electrum-client": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/@mempool/electrum-client/-/electrum-client-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/@mempool/electrum-client/-/electrum-client-1.1.8.tgz",
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mempool/bitcoin": "^3.0.3",
|
|
||||||
"@mempool/electrum-client": "^1.1.7",
|
"@mempool/electrum-client": "^1.1.7",
|
||||||
"@types/ws": "8.2.2",
|
"@types/ws": "8.2.2",
|
||||||
"axios": "0.24.0",
|
"axios": "0.24.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import * as bitcoin from '@mempool/bitcoin';
|
const bitcoin = require('../../rpc-api/index');
|
||||||
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
|
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
|
||||||
|
|
||||||
const nodeRpcCredentials: BitcoinRpcCredentials = {
|
const nodeRpcCredentials: BitcoinRpcCredentials = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import * as bitcoin from '@mempool/bitcoin';
|
const bitcoin = require('../../rpc-api/index');
|
||||||
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
|
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
|
||||||
|
|
||||||
const nodeRpcCredentials: BitcoinRpcCredentials = {
|
const nodeRpcCredentials: BitcoinRpcCredentials = {
|
||||||
|
92
backend/src/rpc-api/commands.ts
Normal file
92
backend/src/rpc-api/commands.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
module.exports = {
|
||||||
|
addMultiSigAddress: 'addmultisigaddress',
|
||||||
|
addNode: 'addnode', // bitcoind v0.8.0+
|
||||||
|
backupWallet: 'backupwallet',
|
||||||
|
createMultiSig: 'createmultisig',
|
||||||
|
createRawTransaction: 'createrawtransaction', // bitcoind v0.7.0+
|
||||||
|
decodeRawTransaction: 'decoderawtransaction', // bitcoind v0.7.0+
|
||||||
|
decodeScript: 'decodescript',
|
||||||
|
dumpPrivKey: 'dumpprivkey',
|
||||||
|
dumpWallet: 'dumpwallet', // bitcoind v0.9.0+
|
||||||
|
encryptWallet: 'encryptwallet',
|
||||||
|
estimateFee: 'estimatefee', // bitcoind v0.10.0x
|
||||||
|
estimatePriority: 'estimatepriority', // bitcoind v0.10.0+
|
||||||
|
generate: 'generate', // bitcoind v0.11.0+
|
||||||
|
getAccount: 'getaccount',
|
||||||
|
getAccountAddress: 'getaccountaddress',
|
||||||
|
getAddedNodeInfo: 'getaddednodeinfo', // bitcoind v0.8.0+
|
||||||
|
getAddressesByAccount: 'getaddressesbyaccount',
|
||||||
|
getBalance: 'getbalance',
|
||||||
|
getBestBlockHash: 'getbestblockhash', // bitcoind v0.9.0+
|
||||||
|
getBlock: 'getblock',
|
||||||
|
getBlockStats: 'getblockstats',
|
||||||
|
getBlockFilter: 'getblockfilter',
|
||||||
|
getBlockchainInfo: 'getblockchaininfo', // bitcoind v0.9.2+
|
||||||
|
getBlockCount: 'getblockcount',
|
||||||
|
getBlockHash: 'getblockhash',
|
||||||
|
getBlockHeader: 'getblockheader',
|
||||||
|
getBlockTemplate: 'getblocktemplate', // bitcoind v0.7.0+
|
||||||
|
getChainTips: 'getchaintips', // bitcoind v0.10.0+
|
||||||
|
getChainTxStats: 'getchaintxstats',
|
||||||
|
getConnectionCount: 'getconnectioncount',
|
||||||
|
getDifficulty: 'getdifficulty',
|
||||||
|
getGenerate: 'getgenerate',
|
||||||
|
getInfo: 'getinfo',
|
||||||
|
getMempoolAncestors: 'getmempoolancestors',
|
||||||
|
getMempoolDescendants: 'getmempooldescendants',
|
||||||
|
getMempoolEntry: 'getmempoolentry',
|
||||||
|
getMempoolInfo: 'getmempoolinfo', // bitcoind v0.10+
|
||||||
|
getMiningInfo: 'getmininginfo',
|
||||||
|
getNetTotals: 'getnettotals',
|
||||||
|
getNetworkInfo: 'getnetworkinfo', // bitcoind v0.9.2+
|
||||||
|
getNetworkHashPs: 'getnetworkhashps', // bitcoind v0.9.0+
|
||||||
|
getNewAddress: 'getnewaddress',
|
||||||
|
getPeerInfo: 'getpeerinfo', // bitcoind v0.7.0+
|
||||||
|
getRawChangeAddress: 'getrawchangeaddress', // bitcoin v0.9+
|
||||||
|
getRawMemPool: 'getrawmempool', // bitcoind v0.7.0+
|
||||||
|
getRawTransaction: 'getrawtransaction', // bitcoind v0.7.0+
|
||||||
|
getReceivedByAccount: 'getreceivedbyaccount',
|
||||||
|
getReceivedByAddress: 'getreceivedbyaddress',
|
||||||
|
getTransaction: 'gettransaction',
|
||||||
|
getTxOut: 'gettxout', // bitcoind v0.7.0+
|
||||||
|
getTxOutProof: 'gettxoutproof', // bitcoind v0.11.0+
|
||||||
|
getTxOutSetInfo: 'gettxoutsetinfo', // bitcoind v0.7.0+
|
||||||
|
getUnconfirmedBalance: 'getunconfirmedbalance', // bitcoind v0.9.0+
|
||||||
|
getWalletInfo: 'getwalletinfo', // bitcoind v0.9.2+
|
||||||
|
help: 'help',
|
||||||
|
importAddress: 'importaddress', // bitcoind v0.10.0+
|
||||||
|
importPrivKey: 'importprivkey',
|
||||||
|
importWallet: 'importwallet', // bitcoind v0.9.0+
|
||||||
|
keypoolRefill: 'keypoolrefill',
|
||||||
|
keyPoolRefill: 'keypoolrefill',
|
||||||
|
listAccounts: 'listaccounts',
|
||||||
|
listAddressGroupings: 'listaddressgroupings', // bitcoind v0.7.0+
|
||||||
|
listLockUnspent: 'listlockunspent', // bitcoind v0.8.0+
|
||||||
|
listReceivedByAccount: 'listreceivedbyaccount',
|
||||||
|
listReceivedByAddress: 'listreceivedbyaddress',
|
||||||
|
listSinceBlock: 'listsinceblock',
|
||||||
|
listTransactions: 'listtransactions',
|
||||||
|
listUnspent: 'listunspent', // bitcoind v0.7.0+
|
||||||
|
lockUnspent: 'lockunspent', // bitcoind v0.8.0+
|
||||||
|
move: 'move',
|
||||||
|
ping: 'ping', // bitcoind v0.9.0+
|
||||||
|
prioritiseTransaction: 'prioritisetransaction', // bitcoind v0.10.0+
|
||||||
|
sendFrom: 'sendfrom',
|
||||||
|
sendMany: 'sendmany',
|
||||||
|
sendRawTransaction: 'sendrawtransaction', // bitcoind v0.7.0+
|
||||||
|
sendToAddress: 'sendtoaddress',
|
||||||
|
setAccount: 'setaccount',
|
||||||
|
setGenerate: 'setgenerate',
|
||||||
|
setTxFee: 'settxfee',
|
||||||
|
signMessage: 'signmessage',
|
||||||
|
signRawTransaction: 'signrawtransaction', // bitcoind v0.7.0+
|
||||||
|
stop: 'stop',
|
||||||
|
submitBlock: 'submitblock', // bitcoind v0.7.0+
|
||||||
|
validateAddress: 'validateaddress',
|
||||||
|
verifyChain: 'verifychain', // bitcoind v0.9.0+
|
||||||
|
verifyMessage: 'verifymessage',
|
||||||
|
verifyTxOutProof: 'verifytxoutproof', // bitcoind v0.11.0+
|
||||||
|
walletLock: 'walletlock',
|
||||||
|
walletPassphrase: 'walletpassphrase',
|
||||||
|
walletPassphraseChange: 'walletpassphrasechange'
|
||||||
|
}
|
61
backend/src/rpc-api/index.ts
Normal file
61
backend/src/rpc-api/index.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
var commands = require('./commands')
|
||||||
|
var rpc = require('./jsonrpc')
|
||||||
|
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
// JsonRPC
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
function Client (opts) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.rpc = new rpc.JsonRPC(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
// cmd
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
Client.prototype.cmd = function () {
|
||||||
|
var args = [].slice.call(arguments)
|
||||||
|
var cmd = args.shift()
|
||||||
|
|
||||||
|
callRpc(cmd, args, this.rpc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
// callRpc
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
function callRpc (cmd, args, rpc) {
|
||||||
|
var fn = args[args.length - 1]
|
||||||
|
|
||||||
|
// If the last argument is a callback, pop it from the args list
|
||||||
|
if (typeof fn === 'function') {
|
||||||
|
args.pop()
|
||||||
|
} else {
|
||||||
|
fn = function () {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpc.call(cmd, args, function () {
|
||||||
|
var args = [].slice.call(arguments)
|
||||||
|
// @ts-ignore
|
||||||
|
args.unshift(null)
|
||||||
|
// @ts-ignore
|
||||||
|
fn.apply(this, args)
|
||||||
|
}, function (err) {
|
||||||
|
fn(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
// Initialize wrappers
|
||||||
|
// ===----------------------------------------------------------------------===//
|
||||||
|
(function () {
|
||||||
|
for (var protoFn in commands) {
|
||||||
|
(function (protoFn) {
|
||||||
|
Client.prototype[protoFn] = function () {
|
||||||
|
var args = [].slice.call(arguments)
|
||||||
|
return callRpc(commands[protoFn], args, this.rpc)
|
||||||
|
}
|
||||||
|
})(protoFn)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
// Export!
|
||||||
|
module.exports.Client = Client;
|
162
backend/src/rpc-api/jsonrpc.ts
Normal file
162
backend/src/rpc-api/jsonrpc.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
var http = require('http')
|
||||||
|
var https = require('https')
|
||||||
|
|
||||||
|
var JsonRPC = function (opts) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.opts = opts || {}
|
||||||
|
// @ts-ignore
|
||||||
|
this.http = this.opts.ssl ? https : http
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonRPC.prototype.call = function (method, params) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var time = Date.now()
|
||||||
|
var requestJSON
|
||||||
|
|
||||||
|
if (Array.isArray(method)) {
|
||||||
|
// multiple rpc batch call
|
||||||
|
requestJSON = []
|
||||||
|
method.forEach(function (batchCall, i) {
|
||||||
|
requestJSON.push({
|
||||||
|
id: time + '-' + i,
|
||||||
|
method: batchCall.method,
|
||||||
|
params: batchCall.params
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// single rpc call
|
||||||
|
requestJSON = {
|
||||||
|
id: time,
|
||||||
|
method: method,
|
||||||
|
params: params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First we encode the request into JSON
|
||||||
|
requestJSON = JSON.stringify(requestJSON)
|
||||||
|
|
||||||
|
// prepare request options
|
||||||
|
var requestOptions = {
|
||||||
|
host: this.opts.host || 'localhost',
|
||||||
|
port: this.opts.port || 8332,
|
||||||
|
method: 'POST',
|
||||||
|
path: '/',
|
||||||
|
headers: {
|
||||||
|
'Host': this.opts.host || 'localhost',
|
||||||
|
'Content-Length': requestJSON.length
|
||||||
|
},
|
||||||
|
agent: false,
|
||||||
|
rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.opts.ssl && this.opts.sslCa) {
|
||||||
|
// @ts-ignore
|
||||||
|
requestOptions.ca = this.opts.sslCa
|
||||||
|
}
|
||||||
|
|
||||||
|
// use HTTP auth if user and password set
|
||||||
|
if (this.opts.user && this.opts.pass) {
|
||||||
|
// @ts-ignore
|
||||||
|
requestOptions.auth = this.opts.user + ':' + this.opts.pass
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we'll make a request to the server
|
||||||
|
var cbCalled = false
|
||||||
|
var request = this.http.request(requestOptions)
|
||||||
|
|
||||||
|
// start request timeout timer
|
||||||
|
var reqTimeout = setTimeout(function () {
|
||||||
|
if (cbCalled) return
|
||||||
|
cbCalled = true
|
||||||
|
request.abort()
|
||||||
|
var err = new Error('ETIMEDOUT')
|
||||||
|
// @ts-ignore
|
||||||
|
err.code = 'ETIMEDOUT'
|
||||||
|
reject(err)
|
||||||
|
}, this.opts.timeout || 30000)
|
||||||
|
|
||||||
|
// set additional timeout on socket in case of remote freeze after sending headers
|
||||||
|
request.setTimeout(this.opts.timeout || 30000, function () {
|
||||||
|
if (cbCalled) return
|
||||||
|
cbCalled = true
|
||||||
|
request.abort()
|
||||||
|
var err = new Error('ESOCKETTIMEDOUT')
|
||||||
|
// @ts-ignore
|
||||||
|
err.code = 'ESOCKETTIMEDOUT'
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
request.on('error', function (err) {
|
||||||
|
if (cbCalled) return
|
||||||
|
cbCalled = true
|
||||||
|
clearTimeout(reqTimeout)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
request.on('response', function (response) {
|
||||||
|
clearTimeout(reqTimeout)
|
||||||
|
|
||||||
|
// We need to buffer the response chunks in a nonblocking way.
|
||||||
|
var buffer = ''
|
||||||
|
response.on('data', function (chunk) {
|
||||||
|
buffer = buffer + chunk
|
||||||
|
})
|
||||||
|
// When all the responses are finished, we decode the JSON and
|
||||||
|
// depending on whether it's got a result or an error, we call
|
||||||
|
// emitSuccess or emitError on the promise.
|
||||||
|
response.on('end', function () {
|
||||||
|
var err
|
||||||
|
|
||||||
|
if (cbCalled) return
|
||||||
|
cbCalled = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
var decoded = JSON.parse(buffer)
|
||||||
|
} catch (e) {
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
err = new Error('Invalid params, response status code: ' + response.statusCode)
|
||||||
|
err.code = -32602
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
err = new Error('Problem parsing JSON response from server')
|
||||||
|
err.code = -32603
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(decoded)) {
|
||||||
|
decoded = [decoded]
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate over each response, normally there will be just one
|
||||||
|
// unless a batch rpc call response is being processed
|
||||||
|
decoded.forEach(function (decodedResponse, i) {
|
||||||
|
if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) {
|
||||||
|
if (reject) {
|
||||||
|
err = new Error(decodedResponse.error.message || '')
|
||||||
|
if (decodedResponse.error.code) {
|
||||||
|
err.code = decodedResponse.error.code
|
||||||
|
}
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
} else if (decodedResponse.hasOwnProperty('result')) {
|
||||||
|
// @ts-ignore
|
||||||
|
resolve(decodedResponse.result, response.headers)
|
||||||
|
} else {
|
||||||
|
if (reject) {
|
||||||
|
err = new Error(decodedResponse.error.message || '')
|
||||||
|
if (decodedResponse.error.code) {
|
||||||
|
err.code = decodedResponse.error.code
|
||||||
|
}
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
request.end(requestJSON);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.JsonRPC = JsonRPC
|
Loading…
x
Reference in New Issue
Block a user