mirror of
https://github.com/fullstack-cash/bch-api.git
synced 2026-09-21 16:52:04 -07:00
Merge pull request #134 from Permissionless-Software-Foundation/ct-unstable
feat(send transaction): Allowing specific node for broadcasting txs
This commit is contained in:
@@ -140,7 +140,7 @@ class RawTransactions {
|
|||||||
const options = _this.routeUtils.getAxiosOptions()
|
const options = _this.routeUtils.getAxiosOptions()
|
||||||
|
|
||||||
// Loop through each height and creates an array of requests to call in parallel
|
// Loop through each height and creates an array of requests to call in parallel
|
||||||
const promises = hexes.map(async hex => {
|
const promises = hexes.map(async (hex) => {
|
||||||
options.data.id = 'decoderawtransaction'
|
options.data.id = 'decoderawtransaction'
|
||||||
options.data.method = 'decoderawtransaction'
|
options.data.method = 'decoderawtransaction'
|
||||||
options.data.params = [hex]
|
options.data.params = [hex]
|
||||||
@@ -152,7 +152,7 @@ class RawTransactions {
|
|||||||
const axiosResult = await _this.axios.all(promises)
|
const axiosResult = await _this.axios.all(promises)
|
||||||
|
|
||||||
// Retrieve the data part of the result.
|
// Retrieve the data part of the result.
|
||||||
const result = axiosResult.map(x => x.data.result)
|
const result = axiosResult.map((x) => x.data.result)
|
||||||
|
|
||||||
res.status(200)
|
res.status(200)
|
||||||
return res.json(result)
|
return res.json(result)
|
||||||
@@ -254,7 +254,7 @@ class RawTransactions {
|
|||||||
const options = _this.routeUtils.getAxiosOptions()
|
const options = _this.routeUtils.getAxiosOptions()
|
||||||
|
|
||||||
// Loop through each hex and create an array of promises
|
// Loop through each hex and create an array of promises
|
||||||
const promises = hexes.map(async hex => {
|
const promises = hexes.map(async (hex) => {
|
||||||
options.data.id = 'decodescript'
|
options.data.id = 'decodescript'
|
||||||
options.data.method = 'decodescript'
|
options.data.method = 'decodescript'
|
||||||
options.data.params = [hex]
|
options.data.params = [hex]
|
||||||
@@ -267,7 +267,7 @@ class RawTransactions {
|
|||||||
const resolved = await Promise.all(promises)
|
const resolved = await Promise.all(promises)
|
||||||
|
|
||||||
// Retrieve the data from each resolved promise.
|
// Retrieve the data from each resolved promise.
|
||||||
const result = resolved.map(x => x.data.result)
|
const result = resolved.map((x) => x.data.result)
|
||||||
|
|
||||||
res.status(200)
|
res.status(200)
|
||||||
return res.json(result)
|
return res.json(result)
|
||||||
@@ -348,7 +348,7 @@ class RawTransactions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each txid and create an array of promises
|
// Loop through each txid and create an array of promises
|
||||||
const promises = txids.map(async txid =>
|
const promises = txids.map(async (txid) =>
|
||||||
_this.getRawTransactionsFromNode(txid, verbose)
|
_this.getRawTransactionsFromNode(txid, verbose)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -436,7 +436,8 @@ class RawTransactions {
|
|||||||
return res.json({ error: 'hex must be an array' })
|
return res.json({ error: 'hex must be an array' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = _this.routeUtils.getAxiosOptions()
|
let options = _this.routeUtils.getAxiosOptions()
|
||||||
|
options = _this.sendTxOptions(options)
|
||||||
|
|
||||||
// Enforce array size rate limits
|
// Enforce array size rate limits
|
||||||
if (!_this.routeUtils.validateArraySize(req, hexes)) {
|
if (!_this.routeUtils.validateArraySize(req, hexes)) {
|
||||||
@@ -536,7 +537,8 @@ class RawTransactions {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = _this.routeUtils.getAxiosOptions()
|
let options = _this.routeUtils.getAxiosOptions()
|
||||||
|
options = _this.sendTxOptions(options)
|
||||||
|
|
||||||
// RPC call
|
// RPC call
|
||||||
options.data.id = 'sendrawtransaction'
|
options.data.id = 'sendrawtransaction'
|
||||||
@@ -557,6 +559,28 @@ class RawTransactions {
|
|||||||
return _this.errorHandler(err, res)
|
return _this.errorHandler(err, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method modifies the default axios options. It attempts to inject
|
||||||
|
// a specific full node to use when broadcasting transactions. This is useful
|
||||||
|
// because it leverages the built-in protections that a full node has against
|
||||||
|
// accidental double spends. It mitigates a corner-case when rapidly spending
|
||||||
|
// TXs on load balanced nodes. By piping all TX sends through a single node,
|
||||||
|
// accidental double spends can be reduced.
|
||||||
|
sendTxOptions (options) {
|
||||||
|
try {
|
||||||
|
if (process.env.RPC_SENDURL) {
|
||||||
|
console.log(`original options: ${JSON.stringify(options, null, 2)}`)
|
||||||
|
options.baseURL = process.env.RPC_SENDURL
|
||||||
|
|
||||||
|
console.log(`modified options: ${JSON.stringify(options, null, 2)}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
} catch (err) {
|
||||||
|
wlogger.error('Error in rawtransactions.js/sendTxOptions()')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RawTransactions
|
module.exports = RawTransactions
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ export RPC_BASEURL=http://$RPC_IP/
|
|||||||
export RPC_USERNAME=bitcoin
|
export RPC_USERNAME=bitcoin
|
||||||
export RPC_PASSWORD=password
|
export RPC_PASSWORD=password
|
||||||
|
|
||||||
|
# (optional) If load-balancing multiple full nodes, it's best to pick a single
|
||||||
|
# one for broadcasting transactions to the network. Prevents accidental
|
||||||
|
# double spends.
|
||||||
|
#export RPC_SENDURL=http://$RPC_IP/
|
||||||
|
|
||||||
# SLPDB
|
# SLPDB
|
||||||
export SLPDB_PASS_GP=somelongpassword
|
export SLPDB_PASS_GP=somelongpassword
|
||||||
export SLPDB_URL=http://<SLPDB IP>:12300/
|
export SLPDB_URL=http://<SLPDB IP>:12300/
|
||||||
|
|||||||
@@ -1047,10 +1047,12 @@ describe('#Raw-Transactions', () => {
|
|||||||
// Save the existing RPC URL.
|
// Save the existing RPC URL.
|
||||||
const savedUrl = process.env.BITCOINCOM_BASEURL
|
const savedUrl = process.env.BITCOINCOM_BASEURL
|
||||||
const savedUrl2 = process.env.RPC_BASEURL
|
const savedUrl2 = process.env.RPC_BASEURL
|
||||||
|
const savedUrl3 = process.env.RPC_SENDURL
|
||||||
|
|
||||||
// Manipulate the URL to cause a 500 network error.
|
// Manipulate the URL to cause a 500 network error.
|
||||||
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/api/'
|
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/api/'
|
||||||
process.env.RPC_BASEURL = 'http://fakeurl/api/'
|
process.env.RPC_BASEURL = 'http://fakeurl/api/'
|
||||||
|
process.env.RPC_SENDURL = 'http://fakeurl/api/'
|
||||||
|
|
||||||
req.params.hex =
|
req.params.hex =
|
||||||
'020000000136697692fed77bc4f5b6885295d0c56d1d0280fb578f445ce42be4eb6db381f2010000006a4730440220473adba0e7da14f0abf4817bbd591741ecb8da6544b998f10341f6704f5f05280220405221c626cb7edcf333367ebd469aff3f5a2169e37ee58eebb811ffc2fbc9e0412102202ff86325c5d903171fa5a2895c4efb3765105115460dc96f113048ddb69b47feffffff027a621b00000000001976a914e0a8ffc3b91e35f46618d6db90f66397989abf0588ac38041300000000001976a914a741f282af390bc7ea8c4375a3a56401d668564288ac2c330900'
|
'020000000136697692fed77bc4f5b6885295d0c56d1d0280fb578f445ce42be4eb6db381f2010000006a4730440220473adba0e7da14f0abf4817bbd591741ecb8da6544b998f10341f6704f5f05280220405221c626cb7edcf333367ebd469aff3f5a2169e37ee58eebb811ffc2fbc9e0412102202ff86325c5d903171fa5a2895c4efb3765105115460dc96f113048ddb69b47feffffff027a621b00000000001976a914e0a8ffc3b91e35f46618d6db90f66397989abf0588ac38041300000000001976a914a741f282af390bc7ea8c4375a3a56401d668564288ac2c330900'
|
||||||
@@ -1060,6 +1062,7 @@ describe('#Raw-Transactions', () => {
|
|||||||
// Restore the saved URL.
|
// Restore the saved URL.
|
||||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||||
process.env.RPC_BASEURL = savedUrl2
|
process.env.RPC_BASEURL = savedUrl2
|
||||||
|
process.env.RPC_SENDURL = savedUrl3
|
||||||
|
|
||||||
assert.isAbove(
|
assert.isAbove(
|
||||||
res.statusCode,
|
res.statusCode,
|
||||||
|
|||||||
Reference in New Issue
Block a user