Compare commits

...
16 Commits
Author SHA1 Message Date
Chris Troutner 2d4159b4cf Merge pull request #41 from Permissionless-Software-Foundation/ct-unstable
fix(Docker): Increasing memory limit to 1GB
2021-10-12 13:39:37 -07:00
Chris Troutner 6dcd1ce5e7 fix(Docker): Increasing memory limit to 1GB 2021-10-12 13:37:31 -07:00
Chris Troutner 6c913b2c36 Merge pull request #40 from Permissionless-Software-Foundation/ct-unstable
fix(dependencies): Using exact versions
2021-10-12 13:34:51 -07:00
Chris Troutner c453705a80 fix(dependencies): Using exact versions 2021-10-12 13:22:16 -07:00
Chris Troutner bb9a2a2408 Merge pull request #54 from Permissionless-Software-Foundation/ct-unstable
fix(dependencies): Using exact versions
2021-10-12 12:46:51 -07:00
Chris Troutner 54709a8c70 fix(dependencies): Using exact versions 2021-10-12 09:56:52 -07:00
Chris Troutner 64135b55a7 fix(tests): Fixing broken unit test 2021-10-11 14:45:09 -07:00
Chris Troutner 1ff4ba440d fixing merge conflicts with upstream 2021-10-11 14:40:22 -07:00
Chris Troutner 72da6203a1 Merge pull request #53 from Permissionless-Software-Foundation/ct-unstable
fix(Dockerfile): Switching to more basic stuff
2021-10-11 14:34:03 -07:00
Chris Troutner e2bc560c7d fix(Dockerfile): Switching to more basic stuff 2021-10-11 13:48:20 -07:00
Chris Troutner e40241bac8 Fixing typo in docker-compose 2021-10-11 09:05:57 -07:00
Chris Troutner 01c8c5c194 Merge pull request #52 from Permissionless-Software-Foundation/ct-unstable
Additional test coverage
2021-10-01 14:11:44 -07:00
Chris Troutner 5eb5ef204e fix(json rpc): Increasing to 100% test coverage 2021-10-01 14:01:08 -07:00
Chris Troutner ee90bc0730 fix(ipfs): Got adapter back to 100% unit test coverage 2021-09-30 15:20:51 -07:00
Chris Troutner 5af068e0d6 fix(ipfs-coord): Got adapter back to 100% test coverage 2021-09-30 15:12:47 -07:00
Chris Troutner 7e228b729e fix(ipfs adapter): Adding unit tests for lock-file error handling 2021-09-30 14:47:17 -07:00
13 changed files with 9458 additions and 3379 deletions
+9203 -3305
View File
File diff suppressed because it is too large Load Diff
+42 -42
View File
@@ -24,51 +24,51 @@
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
"dependencies": {
"@chris.troutner/ipfs": "2.0.2",
"@psf/bch-js": "^4.20.13",
"axios": "^0.21.1",
"bcryptjs": "^2.4.3",
"glob": "^7.1.6",
"ipfs-coord": "^6.7.1",
"jsonrpc-lite": "^2.2.0",
"jsonwebtoken": "^8.5.1",
"jwt-bch-lib": "^1.3.0",
"kcors": "^2.2.2",
"koa": "^2.13.1",
"koa-bodyparser": "^4.3.0",
"koa-convert": "^2.0.0",
"koa-generic-session": "^2.1.1",
"koa-logger": "^3.2.1",
"koa-mount": "^4.0.0",
"koa-passport": "^4.1.3",
"koa-router": "^10.0.0",
"koa-static": "^5.0.0",
"koa2-ratelimit": "^0.9.0",
"line-reader": "^0.4.0",
"mongoose": "^5.11.15",
"node-fetch": "npm:@achingbrain/node-fetch@^2.6.7",
"nodemailer": "^6.4.17",
"passport-local": "^1.0.0",
"public-ip": "^4.0.4",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.0"
"@psf/bch-js": "4.20.13",
"axios": "0.21.1",
"bcryptjs": "2.4.3",
"glob": "7.1.6",
"ipfs-coord": "6.7.2",
"jsonrpc-lite": "2.2.0",
"jsonwebtoken": "8.5.1",
"jwt-bch-lib": "1.3.0",
"kcors": "2.2.2",
"koa": "2.13.1",
"koa-bodyparser": "4.3.0",
"koa-convert": "2.0.0",
"koa-generic-session": "2.1.1",
"koa-logger": "3.2.1",
"koa-mount": "4.0.0",
"koa-passport": "4.1.3",
"koa-router": "10.0.0",
"koa-static": "5.0.0",
"koa2-ratelimit": "0.9.0",
"line-reader": "0.4.0",
"mongoose": "5.11.15",
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
"nodemailer": "6.4.17",
"passport-local": "1.0.0",
"public-ip": "4.0.4",
"winston": "3.3.3",
"winston-daily-rotate-file": "4.5.0"
},
"devDependencies": {
"apidoc": "^0.26.0",
"chai": "^4.3.0",
"coveralls": "^3.1.0",
"apidoc": "0.26.0",
"chai": "4.3.0",
"coveralls": "3.1.0",
"eslint": "7.19.0",
"eslint-config-prettier": "^7.2.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-standard": "^4.0.0",
"husky": "^4.3.8",
"mocha": "^8.2.1",
"nyc": "^15.1.0",
"semantic-release": "^17.4.4",
"sinon": "^9.2.4",
"standard": "^16.0.3",
"uuid": "^8.3.2"
"eslint-config-prettier": "7.2.0",
"eslint-config-standard": "16.0.2",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-standard": "4.0.0",
"husky": "4.3.8",
"mocha": "8.2.1",
"nyc": "15.1.0",
"semantic-release": "17.4.4",
"sinon": "9.2.4",
"standard": "16.0.3",
"uuid": "8.3.2"
},
"release": {
"publish": [
+7
View File
@@ -34,6 +34,13 @@ RUN runuser -l safeuser -c "npm config set prefix '~/.npm-global'"
# Working with npm@7.21.1
RUN npm install -g npm
# Update to the latest version of npm.
# Working with npm@7.21.1
RUN npm install -g npm@7.23.0
# npm mirror to prevent direct dependency on npm.
RUN npm set registry http://94.130.170.209:4873/
# Switch to user account.
#USER safeuser
# Prep 'sudo' commands.
+2 -2
View File
@@ -20,7 +20,7 @@ services:
options:
max-size: '10m'
max-file: '10'
mem_limit: 500mb
mem_limit: 1000mb
links:
- bch-wallet-mongodb
ports:
@@ -29,4 +29,4 @@ services:
- '5668:5668' # IPFS TCP Port
- '5669:5669' # IPFS WS Port
volumes:
- ../data/ipfsdata:/home/safeuser/ipfs-service-provider/.ipfsdata
- ../data/ipfsdata:/home/safeuser/ipfs-bch-wallet-service/.ipfsdata
+5 -10
View File
@@ -10,6 +10,7 @@ class IPFS {
// Encapsulate dependencies
this.ipfsAdapter = new IpfsAdapter()
this.IpfsCoordAdapter = IpfsCoordAdapter
this.process = process
this.ipfsCoordAdapter = {} // placeholder
@@ -47,16 +48,10 @@ class IPFS {
} catch (err) {
console.error('Error in adapters/ipfs/index.js/start()')
// If we are not in a test environment.
if (process.env.SVC_ENV !== 'test') {
// If error is due to a lock file issue. Kill the process, so that
// Docker or pm2 has a chance to restart the service.
if (err.message.includes('Lock already being held')) {
console.log(
'Lock file issue with IPFS. Shutting down so that process manager can restart app.'
)
process.exit(1)
}
// If error is due to a lock file issue. Kill the process, so that
// Docker or pm2 has a chance to restart the service.
if (err.message.includes('Lock already being held')) {
this.process.exit(1)
}
throw err
+2 -1
View File
@@ -36,6 +36,7 @@ class IpfsCoordAdapter {
this.ipfsCoord = {}
// this.rpc = new JSONRPC()
this.config = config
this.publicIp = publicIp
// Properties of this class instance.
this.isReady = false
@@ -49,7 +50,7 @@ class IpfsCoordAdapter {
// If configured as a Circuit Relay, get the public IP addresses for this node.
if (this.config.isCircuitRelay) {
try {
const ip4 = await publicIp.v4()
const ip4 = await this.publicIp.v4()
// const ip6 = await publicIp.v6()
circuitRelayInfo.ip4 = ip4
+2
View File
@@ -77,6 +77,8 @@ class IpfsAdapter {
async stop () {
await this.ipfs.stop()
return true
}
}
+10 -6
View File
@@ -58,7 +58,7 @@ class JSONRPC {
wlogger.info(
'Warning: Can not send JSON RPC response. Can not determine which peer this message came from.'
)
return
return false
}
// Attempt to parse the incoming data as a JSON RPC string.
@@ -68,22 +68,24 @@ class JSONRPC {
// Exit quietly if the incoming string is an invalid JSON RPC string.
if (parsedData.type === 'invalid') {
wlogger.info('Rejecting invalid JSON RPC command.')
return
return false
}
// Check for duplicate entries with same 'id' value.
const alreadyProcessed = _this._checkIfAlreadyProcessed(parsedData)
if (alreadyProcessed) {
return
return false
} else {
// console.log(`parsedData: ${JSON.stringify(parsedData, null, 2)}`)
// This node will regularly ping known circuit relays with an /about
// JSON RPC call. These will be handled by ipfs-coord, but will percolate
// up to ipfs-coord. Ignore these messages.
// up to this library. Ignore these messages.
if (
parsedData.type.includes('success') &&
parsedData.payload.method === undefined
) {
return
return false
}
// Log the incoming JSON RPC command.
@@ -156,6 +158,8 @@ class JSONRPC {
// If the ID is new, the function adds it to the cache and return false.
_checkIfAlreadyProcessed (data) {
try {
// console.log('data: ', data)
const id = data.payload.id
// Check if the hash is in the array of already processed message.
@@ -175,7 +179,7 @@ class JSONRPC {
return alreadyProcessed
} catch (err) {
console.error('Error in _checkIfAlreadyProcessed: ', err)
return false
return true
}
}
+28 -11
View File
@@ -62,6 +62,20 @@ describe('#IPFS', () => {
assert.equal(result, true)
})
it('should get the public IP address if this node is a Circuit Relay', async () => {
// Mock dependencies.
uut.IpfsCoord = IPFSCoordMock
sandbox.stub(uut.publicIp, 'v4').returns('123')
// Force Circuit Relay
uut.config.isCircuitRelay = true
const result = await uut.start()
// console.log('result: ', result)
assert.equal(result, true)
})
})
describe('#attachRPCRouter', () => {
@@ -86,16 +100,19 @@ describe('#IPFS', () => {
uut.attachRPCRouter(router)
})
// it('should throw an error if ipfs-coord has not been instantiated', () => {
// try {
// const router = console.log
//
// uut.attachRPCRouter(router)
//
// assert.fail('Unexpected code path')
// } catch (err) {
// assert.include(err.message, 'Cannot read property')
// }
// })
it('should catch and throw an error', () => {
try {
// Force an error
delete uut.ipfsCoord.adapters
const router = console.log
uut.attachRPCRouter(router)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'Cannot read property')
}
})
})
})
+22 -1
View File
@@ -4,6 +4,7 @@
const assert = require('chai').assert
const sinon = require('sinon')
const BCHJS = require('@psf/bch-js')
const IPFSLib = require('../../../src/adapters/ipfs')
const IPFSMock = require('../mocks/ipfs-mock')
@@ -12,9 +13,11 @@ const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
describe('#IPFS-adapter-index', () => {
let uut
let sandbox
let bchjs
beforeEach(() => {
uut = new IPFSLib()
bchjs = new BCHJS()
uut = new IPFSLib({ bchjs })
sandbox = sinon.createSandbox()
})
@@ -59,5 +62,23 @@ describe('#IPFS-adapter-index', () => {
assert.include(err.message, 'test error')
}
})
it('should handle lock-file errors', async () => {
try {
// Force an error
sandbox
.stub(uut.ipfsAdapter, 'start')
.rejects(new Error('Lock already being held'))
// Prevent process from exiting
sandbox.stub(uut.process, 'exit').returns()
await uut.start({ bchjs })
assert.fail('Unexpected code path.')
} catch (err) {
assert.include(err.message, 'Lock already being held')
}
})
})
})
+13
View File
@@ -47,4 +47,17 @@ describe('#IPFS-adapter', () => {
}
})
})
describe('#stop', () => {
it('should stop the IPFS node', async () => {
// Mock dependencies
uut.ipfs = {
stop: () => {}
}
const result = await uut.stop()
assert.equal(result, true)
})
})
})
@@ -207,5 +207,120 @@ describe('#JSON RPC', () => {
assert.equal(obj.result.method, 'bch')
assert.equal(obj.id, id)
})
it('should exit quietly for duplicate RPC message', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Call router once.
await uut.router(str, 'peerA')
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
assert.equal(result, false)
})
it('should ignore metric queries from ipfs-coord', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Force the RPC type to be 'success', to indicate an RPC that was
// processed internal to ipfs-coord.
sandbox.stub(uut.jsonrpc, 'parse').returns({
payload: {},
type: 'success'
})
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
assert.equal(result, false)
})
it('should report errors when trying to send messages to peers', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Force issue with sendPrivateMessage()
sandbox
.stub(uut.ipfsCoord.useCases.peer, 'sendPrivateMessage')
.rejects('test error')
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
// console.log('result: ', result)
assert.property(result, 'from')
assert.property(result, 'retStr')
})
})
describe('#_checkIfAlreadyProcessed', () => {
it('should return false the first time an RPC command is seen', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, false)
})
it('should return true the second time an RPC command is seen', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
// First call.
uut._checkIfAlreadyProcessed(data)
// Second call.
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, true)
})
it('should push out old data from the cache for new data', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
uut.MSG_CACHE_SIZE = 0
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, false)
})
it('should return true on error', () => {
const result = uut._checkIfAlreadyProcessed()
assert.equal(result, true)
})
})
})
+7 -1
View File
@@ -7,7 +7,13 @@ const ipfs = {
ipfs: {}
},
ipfsCoordAdapter: {
ipfsCoord: {}
ipfsCoord: {
useCases: {
peer: {
sendPrivateMessage: () => {}
}
}
}
}
}