mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service.git
synced 2026-09-21 16:52:03 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e90d664761 | ||
|
|
fc11e701e4 | ||
|
|
3c7ebef8a7 | ||
|
|
5d70c89f2d | ||
|
|
7149c0a824 | ||
|
|
74c6bc5737 | ||
|
|
bac6c8b1e9 | ||
|
|
9e7d955bc4 | ||
|
|
af7c4464bb | ||
|
|
cfb128f3c8 | ||
|
|
451a828a05 | ||
|
|
678bc7015c | ||
|
|
013aa97143 | ||
|
|
45b7e480b7 | ||
|
|
09772bae29 | ||
|
|
c01130fcc7 | ||
|
|
2d4159b4cf | ||
|
|
6dcd1ce5e7 |
Generated
+727
-2418
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -24,11 +24,11 @@
|
||||
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
|
||||
"dependencies": {
|
||||
"@chris.troutner/ipfs": "2.0.2",
|
||||
"@psf/bch-js": "4.20.13",
|
||||
"@psf/bch-js": "4.20.28",
|
||||
"axios": "0.21.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"glob": "7.1.6",
|
||||
"ipfs-coord": "6.7.2",
|
||||
"ipfs-coord": "6.7.4",
|
||||
"jsonrpc-lite": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jwt-bch-lib": "1.3.0",
|
||||
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
options:
|
||||
max-size: '10m'
|
||||
max-file: '10'
|
||||
mem_limit: 500mb
|
||||
mem_limit: 1000mb
|
||||
links:
|
||||
- bch-wallet-mongodb
|
||||
ports:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# This script is an example for running a generic ipfs-service-provider instance.
|
||||
|
||||
# Ports
|
||||
export PORT=5001 # REST API port
|
||||
export PORT=5002 # REST API port
|
||||
export IPFS_TCP_PORT=5268
|
||||
export IPFS_WS_PORT=5269
|
||||
|
||||
|
||||
@@ -51,6 +51,11 @@ class IpfsAdapter {
|
||||
`/ip4/0.0.0.0/tcp/${this.config.ipfsTcpPort}`,
|
||||
`/ip4/0.0.0.0/tcp/${this.config.ipfsWsPort}/ws`
|
||||
]
|
||||
},
|
||||
Datastore: {
|
||||
StorageMax: '2GB',
|
||||
StorageGCWatermark: 50,
|
||||
GCPeriod: '15m'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ class BCHRPC {
|
||||
case 'transaction':
|
||||
await this.rateLimit.limiter(rpcData.from)
|
||||
return await this.transaction(rpcData)
|
||||
|
||||
case 'pubkey':
|
||||
await this.rateLimit.limiter(rpcData.from)
|
||||
return await this.pubKey(rpcData)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error in BCHRPC/rpcRouter()')
|
||||
@@ -327,6 +331,7 @@ class BCHRPC {
|
||||
// console.log('createUser rpcData: ', rpcData)
|
||||
|
||||
const addr = rpcData.payload.params.address
|
||||
console.log('addr: ', addr)
|
||||
|
||||
const data = await this.bchjs.Utxo.get(addr)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
@@ -400,13 +405,24 @@ class BCHRPC {
|
||||
return retObj
|
||||
} catch (err) {
|
||||
console.error('Error in JSON RPC BCH broadcast()')
|
||||
console.log('error: ', err)
|
||||
// throw err
|
||||
|
||||
// bch-api will sometimes return an error message, not an error object.
|
||||
let message = ''
|
||||
if (!err.message && err.error) {
|
||||
// Full node error
|
||||
message = err.error
|
||||
} else {
|
||||
// Normal error
|
||||
message = err.message
|
||||
}
|
||||
|
||||
// Return an error response
|
||||
return {
|
||||
success: false,
|
||||
status: 422,
|
||||
message: err.message,
|
||||
message,
|
||||
endpoint: 'broadcast'
|
||||
}
|
||||
}
|
||||
@@ -532,6 +548,78 @@ class BCHRPC {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {JSON} /bch PubKey
|
||||
* @apiPermission public
|
||||
* @apiName PubKey
|
||||
* @apiGroup JSON BCH
|
||||
* @apiDescription Get the public key from an address.
|
||||
* Given an address the endpoint will return an object with the
|
||||
* following properties
|
||||
*
|
||||
* - jsonrpc: "" - jsonrpc version
|
||||
* - id: "" - jsonrpc id
|
||||
* - result: {} - Result of the petition with the RPC information
|
||||
* - success: - Request status
|
||||
* - publickey: - Address public key
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "pubkey", "address": "bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk"}}
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* {
|
||||
* "jsonrpc":"2.0",
|
||||
* "id":"555",
|
||||
* "result":{
|
||||
* "method":"bch",
|
||||
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
|
||||
* "value":{
|
||||
* "success": true,
|
||||
* "status": 200,
|
||||
* "endpoint": "pubkey",
|
||||
* "pubkey": {
|
||||
* "success": true,
|
||||
* "publicKey": "033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee"
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
async pubKey (rpcData) {
|
||||
try {
|
||||
// console.log('createUser rpcData: ', rpcData)
|
||||
|
||||
const address = rpcData.payload.params.address
|
||||
|
||||
const data = await this.bchjs.encryption.getPubKey(address)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
const retObj = {
|
||||
success: true,
|
||||
status: 200,
|
||||
endpoint: 'pubkey',
|
||||
pubkey: data
|
||||
}
|
||||
// retObj.status = 200
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
console.error('Error in JSON RPC BCH pubKey()')
|
||||
// throw err
|
||||
let error = err
|
||||
if (err.error && typeof err.error === 'string') {
|
||||
error = new Error(err.error)
|
||||
}
|
||||
// Return an error response
|
||||
return {
|
||||
success: false,
|
||||
status: 422,
|
||||
message: error.message,
|
||||
endpoint: 'pubkey'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BCHRPC
|
||||
|
||||
@@ -94,7 +94,7 @@ class BCHRESTController {
|
||||
* @api {post} /bch/balance Balance
|
||||
* @apiName Balance
|
||||
* @apiGroup REST BCH
|
||||
* @apiDescription Devuelve el balance de un address o un array de adresses.
|
||||
* @apiDescription Returns the balance of an address or an array of addresses.
|
||||
*
|
||||
* Given the 'addresses' property returns an array of objects
|
||||
* with the following properties
|
||||
@@ -378,6 +378,57 @@ class BCHRESTController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /bch/pubkey PubKey
|
||||
* @apiName PubKey
|
||||
* @apiGroup REST BCH
|
||||
* @apiDescription Get the public key from an address
|
||||
*
|
||||
* Given the 'address' param returns an object
|
||||
* with the following properties
|
||||
*
|
||||
* - success : - Request status
|
||||
* - publicKey : '' - Public key of the provided address
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5001/bch/pubkey/bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "success":true,
|
||||
* "publicKey": '033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee'
|
||||
* }
|
||||
*
|
||||
* @apiError UnprocessableEntity Missing required parameters
|
||||
*
|
||||
* @apiErrorExample {json} Error-Response:
|
||||
* HTTP/1.1 422 Unprocessable Entity
|
||||
* {
|
||||
* "status": 422,
|
||||
* "error": "Unprocessable Entity"
|
||||
* }
|
||||
*/
|
||||
async pubKey (ctx) {
|
||||
try {
|
||||
const address = ctx.params.address
|
||||
console.log(`pubKey address: ${address}`)
|
||||
|
||||
const pubkey = await _this.bchjs.encryption.getPubKey(address)
|
||||
// console.log(`pubkey: ${JSON.stringify(pubkey, null, 2)}`)
|
||||
|
||||
ctx.body = pubkey
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
let error = err
|
||||
if (err.error && typeof err.error === 'string') {
|
||||
error = new Error(err.error)
|
||||
}
|
||||
_this.handleError(ctx, error)
|
||||
}
|
||||
}
|
||||
|
||||
// DRY error handler
|
||||
handleError (ctx, err) {
|
||||
// If an HTTP status is specified by the buisiness logic, use that.
|
||||
|
||||
@@ -50,6 +50,7 @@ class BCHRouter {
|
||||
this.router.post('/utxos', this.bchRESTController.utxos)
|
||||
this.router.post('/broadcast', this.bchRESTController.broadcast)
|
||||
this.router.post('/transaction', this.bchRESTController.transaction)
|
||||
this.router.get('/pubkey/:address', this.bchRESTController.pubKey)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
|
||||
@@ -155,6 +155,24 @@ describe('#BCHRPC', () => {
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
it('should route to the pubkey method', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut, 'pubKey').resolves(true)
|
||||
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const rpcCall = jsonrpc.request(id, 'bch', {
|
||||
endpoint: 'pubkey'
|
||||
})
|
||||
const jsonStr = JSON.stringify(rpcCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
rpcData.from = 'Origin request'
|
||||
|
||||
const result = await uut.bchRouter(rpcData)
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should return 500 status on routing issue', async () => {
|
||||
// Mock dependencies
|
||||
@@ -420,4 +438,81 @@ describe('#BCHRPC', () => {
|
||||
assert.equal(response.endpoint, 'transaction')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#pubKey', () => {
|
||||
it('should return data from bchjs', async () => {
|
||||
// Mock dependencies
|
||||
const mock = { success: true, publicKey: '033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee' }
|
||||
sandbox.stub(uut.bchjs.encryption, 'getPubKey').resolves(mock)
|
||||
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const rpcCall = jsonrpc.request(id, 'bch', {
|
||||
endpoint: 'pubkey',
|
||||
address: 'bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk'
|
||||
})
|
||||
const jsonStr = JSON.stringify(rpcCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
|
||||
const response = await uut.pubKey(rpcData)
|
||||
|
||||
assert.equal(response.success, true)
|
||||
assert.equal(response.status, 200)
|
||||
|
||||
assert.property(response, 'pubkey')
|
||||
|
||||
const pubKey = response.pubkey
|
||||
assert.property(pubKey, 'publicKey')
|
||||
assert.equal(pubKey.publicKey, mock.publicKey)
|
||||
})
|
||||
it('should throw an error if public key is not found', async () => {
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(uut.bchjs.encryption, 'getPubKey')
|
||||
.rejects({ success: false, error: 'No transaction history.' })
|
||||
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const rpcCall = jsonrpc.request(id, 'bch', {
|
||||
endpoint: 'pubkey',
|
||||
address: 'bitcoincash:qrnx7l2e6yejgswehf54gs30ljzumnhqdqgn8yscr2'
|
||||
})
|
||||
const jsonStr = JSON.stringify(rpcCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
|
||||
const response = await uut.pubKey(rpcData)
|
||||
// console.log('response: ', response)
|
||||
|
||||
assert.equal(response.success, false)
|
||||
assert.equal(response.status, 422)
|
||||
assert.equal(response.message, 'No transaction history.')
|
||||
assert.equal(response.endpoint, 'pubkey')
|
||||
})
|
||||
it('should return an error for invalid input', async () => {
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(uut.bchjs.encryption, 'getPubKey')
|
||||
.rejects(new Error('Invalid data'))
|
||||
|
||||
// Generate the parsed data that the main router would pass to this
|
||||
// endpoint.
|
||||
const id = uid()
|
||||
const rpcCall = jsonrpc.request(id, 'bch', {
|
||||
endpoint: 'pubkey',
|
||||
address: 'bitcoincash'
|
||||
})
|
||||
const jsonStr = JSON.stringify(rpcCall, null, 2)
|
||||
const rpcData = jsonrpc.parse(jsonStr)
|
||||
|
||||
const response = await uut.pubKey(rpcData)
|
||||
// console.log('response: ', response)
|
||||
|
||||
assert.equal(response.success, false)
|
||||
assert.equal(response.status, 422)
|
||||
assert.equal(response.message, 'Invalid data')
|
||||
assert.equal(response.endpoint, 'pubkey')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -233,6 +233,56 @@ describe('#BCH-REST-Router', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#pubKey', () => {
|
||||
it('should return data from bchjs', async () => {
|
||||
// Mock dependencies
|
||||
const mock = { success: true, publicKey: '033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee' }
|
||||
sandbox.stub(uut.bchjs.encryption, 'getPubKey').resolves(mock)
|
||||
|
||||
ctx.params = {
|
||||
address: 'bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk'
|
||||
}
|
||||
|
||||
await uut.pubKey(ctx)
|
||||
// console.log('ctx.body: ', ctx.body)
|
||||
|
||||
assert.equal(ctx.body.success, true)
|
||||
assert.equal(ctx.body.publicKey, mock.publicKey)
|
||||
})
|
||||
it('should throw an error if public key is not found', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(uut.bchjs.encryption, 'getPubKey')
|
||||
.rejects({ success: false, error: 'No transaction history.' })
|
||||
|
||||
ctx.params = {
|
||||
address: 'bitcoincash:qrnx7l2e6yejgswehf54gs30ljzumnhqdqgn8yscr2'
|
||||
}
|
||||
await uut.pubKey(ctx)
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'No transaction history')
|
||||
}
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(uut.bchjs.encryption, 'getPubKey')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
ctx.params = {
|
||||
address: 'bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk'
|
||||
}
|
||||
await uut.pubKey(ctx)
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#handleError', () => {
|
||||
it('should pass an error message', () => {
|
||||
try {
|
||||
|
||||
@@ -66,6 +66,9 @@ const bchjs = {
|
||||
},
|
||||
RawTransactions: {
|
||||
sendRawTransaction: () => {}
|
||||
},
|
||||
encryption: {
|
||||
getPubKey: () => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user