diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 857cd18..8890d5a 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -11,11 +11,11 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: "14.x" + node-version: "20.x" cache: "npm" - name: Install dependencies @@ -27,11 +27,11 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: "14.x" + node-version: "20.x" cache: "npm" - name: Install dependencies @@ -39,3 +39,5 @@ jobs: - name: Run tests run: npm test + env: + ELECTRUM_API_KEY: ${{ secrets.ELECTRUM_API_KEY }} diff --git a/example/example.js b/example/example.js index 527911c..8f0fec3 100644 --- a/example/example.js +++ b/example/example.js @@ -4,13 +4,13 @@ async function main() { const client = new ElectrumClient( 'electrum.bitaroo.net', 50002, - 'ssl' + 'ssl', ) try { await client.connect( 'electrum-client-js', // optional client name - '1.4.2' // optional protocol version + '1.4.2', // optional protocol version ) const header = await client.blockchain_headers_subscribe() diff --git a/src/electrum/client.js b/src/electrum/client.js index 88ff218..d1d094c 100644 --- a/src/electrum/client.js +++ b/src/electrum/client.js @@ -4,8 +4,8 @@ const util = require('./util') const keepAliveInterval = 450 * 1000 // 7.5 minutes as recommended by ElectrumX SESSION_TIMEOUT class ElectrumClient extends SocketClient { - constructor(host, port, protocol, options) { - super(host, port, protocol, options) + constructor(host, port, protocol, options, path) { + super(host, port, protocol, options, path) } async connect(clientName, electrumProtocolVersion, persistencePolicy = {maxRetry: 10, callback: null}) { @@ -75,7 +75,7 @@ class ElectrumClient extends SocketClient { } }, keepAliveInterval, - this // pass this context as an argument to function + this, // pass this context as an argument to function ) } } diff --git a/src/socket/socket_client.js b/src/socket/socket_client.js index a21be7b..8eef058 100644 --- a/src/socket/socket_client.js +++ b/src/socket/socket_client.js @@ -6,12 +6,13 @@ const TCPSocketClient = require('./socket_client_tcp') const WebSocketClient = require('./socket_client_ws') class SocketClient { - constructor(host, port, protocol, options) { + constructor(host, port, protocol, options, path) { this.id = 0 this.host = host this.port = port this.protocol = protocol this.options = options + this.path = path || '' this.status = 0 this.callback_message_queue = {} this.events = new EventEmitter() @@ -27,7 +28,7 @@ class SocketClient { break case 'ws': case 'wss': - this.client = new WebSocketClient(this, host, port, protocol, options) + this.client = new WebSocketClient(this, host, port, protocol, options, path) break default: throw new Error(`invalid protocol: [${protocol}]`) diff --git a/src/socket/socket_client_ws.js b/src/socket/socket_client_ws.js index df56529..90d2ddd 100644 --- a/src/socket/socket_client_ws.js +++ b/src/socket/socket_client_ws.js @@ -2,17 +2,18 @@ const W3CWebSocket = require('websocket').w3cwebsocket class WebSocketClient { - constructor(self, host, port, protocol, options) { + constructor(self, host, port, protocol, options, path) { this.self = self this.host = host this.port = port this.protocol = protocol this.options = options + this.path = path || '' this.client = null } async connect() { - const url = `${this.protocol}://${this.host}:${this.port}` + const url = `${this.protocol}://${this.host}:${this.port}${this.path}` // TODO: Add docs // https://github.com/theturtle32/WebSocket-Node/blob/master/docs/W3CWebSocket.md#constructor @@ -21,7 +22,7 @@ class WebSocketClient { undefined, undefined, undefined, - this.options + this.options, ) this.client = client diff --git a/test/config.js b/test/config.js index 06866ff..3407a86 100644 --- a/test/config.js +++ b/test/config.js @@ -1,27 +1,32 @@ -const servers = { - tcp: { - protocol: 'tcp', port: '50001', host: 'electrum.bitaroo.net', +const ELECTRUM_API_KEY = process.env.ELECTRUM_API_KEY + +const servers = [ + { + protocol: 'tcp', + port: 50001, + host: 'electrum.bitaroo.net', }, - ssl: { - protocol: 'ssl', port: '50002', host: 'electrum.bitaroo.net', + { + protocol: 'ssl', + port: 50002, + host: 'electrum.bitaroo.net', }, - ws: { - protocol: 'ws', port: '50003', host: 'electrumx-server.tbtc.svc.cluster.local', + // no server available to test ws:// + { + protocol: 'wss', + port: 8443, + host: 'electrumx-server.tbtc.network', + // FIXME: It's a temporary workaround to get the connection working. + options: {rejectUnauthorized: false}, }, - wss: { - protocol: 'wss', port: '50004', host: 'electrumx-server.tbtc.svc.cluster.local', + { + protocol: 'wss', + port: 443, + host: 'electrum.mainnet.boar.network', + path: `/${ELECTRUM_API_KEY}`, }, -} - -const serversArray = [ - servers.tcp, - servers.ssl, - // FIXME: WebSocket is commented out for CI, until we find public servers for this protocol. - // electrumServers.ws, - // electrumServers.wss, ] module.exports = { servers, - serversArray, } diff --git a/test/integration_test.js b/test/integration_test.js index 9983596..113a272 100644 --- a/test/integration_test.js +++ b/test/integration_test.js @@ -5,76 +5,73 @@ const assert = chai.assert const fs = require('fs') -const config = require('./config') +const {servers} = require('./config') describe('ElectrumClient', async () => { let txData before(async () => { - txData = JSON.parse(await fs.readFileSync('./test/tx.json', 'utf8')) + txData = JSON.parse(fs.readFileSync('./test/tx.json', 'utf8')) }) - context('when connected', async () => { - config.serversArray.forEach((server) => { - describe(`for ${server.protocol} protocol`, async () => { - let client + describe('for all protocols', async () => { + servers.forEach((server) => { + const label = `${server.protocol}://${server.host}:${server.port}${server.path || ''}` + describe(label, async () => { + describe('when connected', async () => { + let client - before(async () => { - client = new ElectrumClient( - server.host, - server.port, - server.protocol, - server.options - ) + before(async () => { + client = new ElectrumClient( + server.host, + server.port, + server.protocol, + server.options, + server.path, + ) - await client - .connect('test_client' + server.protocol, '1.4.2') - .catch((err) => { - console.error( - `failed to connect with config [${JSON.stringify( - server - )}]: [${err}]` - ) - }) - }) + await client.connect('test_client' + server.protocol, '1.4.2') + }) - after(async () => { - await client.close() - }) + after(async () => { + await client.close() + }) - it('request returns result', async () => { - const expectedResult = txData.hex - const result = await client.blockchain_transaction_get(txData.hash) + it('request returns result', async () => { + const expectedResult = txData.hex + const result = await client.blockchain_transaction_get(txData.hash) - assert.equal(result, expectedResult, 'unexpected result') + assert.equal(result, expectedResult, 'unexpected result') + }) }) - }) - }) - }) - context('when not connected', async () => { - before(async () => { - const server = config.servers.tcp + describe('when not connected', async () => { + let client - client = new ElectrumClient( - server.host, - server.port, - server.protocol, - server.options - ) - }) + before(async () => { + client = new ElectrumClient( + server.host, + server.port, + server.protocol, + server.options, + server.path, + ) + }) - it('request throws error', async () => { - await client.blockchain_transaction_get(txData.hash).then( - (value) => { - // onFulfilled - assert.fail('not failed as expected') - }, - (reason) => { - // onRejected - assert.include(reason.toString(), `connection not established`) - } - ) + it('request throws error', async () => { + await client.blockchain_transaction_get(txData.hash).then( + (value) => { + // onFulfilled + assert.fail('not failed as expected') + }, + (reason) => { + // onRejected + assert.include(reason.toString(), `connection not established`) + }, + ) + }) + }) + }) }) }) // TODO: Add tests diff --git a/test/tx.json b/test/tx.json index 6997a67..29e2a78 100644 --- a/test/tx.json +++ b/test/tx.json @@ -1,4 +1,4 @@ { - "hash": "d60033c5cf5c199208a9c656a29967810c4e428c22efb492fdd816e6a0a1e548", - "hex": "010000000001011746bd867400f3494b8f44c24b83e1aa58c4f0ff25b4a61cffeffd4bc0f9ba300000000000ffffffff024897070000000000220020a4333e5612ab1a1043b25755c89b16d55184a42f81799e623e6bc39db8539c180000000000000000166a14edb1b5c2f39af0fec151732585b1049b07895211024730440220276e0ec78028582054d86614c65bc4bf85ff5710b9d3a248ca28dd311eb2fa6802202ec950dd2a8c9435ff2d400cc45d7a4854ae085f49e05cc3f503834546d410de012103732783eef3af7e04d3af444430a629b16a9261e4025f52bf4d6d026299c37c7400000000" + "hash": "a000b3082c3e177a5ba2064b74a87ef830f8107f3fb9f9274dde4ed79bb93008", + "hex": "02000000000103570412f893ca49eb1c42b6d22e385e8e281220eeb4b9526a77e3394a524a2bb80000000000ffffffffc7bf20bcf7643a91cb26410477a1066f1552c63b0f74175bb2a3169b2388cd2e0000000000ffffffffce1a14ab30f6e28ea6ee79469fed744b6b50c6e54583679da8ed00580bbe069f0300000000ffffffff0240420f0000000000220020f531e77ae36368687c262a7da1a89d7f22c48ab709cd83afe08e34c6db6952b90f4900000000000016001409da2b5bbfbe73460db900e09ec6745b65877c0b0248304502210095d6517ecaf5278c692ec72298088ac50f0e9f5afebd7418b4d8ad7cc59fa04202204bbb7c509344cee31982da546f01ab2cf2436425637769b1d4d9a4687ea4ff0601210387947b950113f035a5ffc732912670ebb34db4a97f6e3dd4ada2205b3994a2340248304502210090100e56b3c97b496fd9f9e83b31c26bd957be254826ff9bead8a95081e1851f02200c9d15825c4fa8ceb56828e8338b008791cb6d241f7f597e6587038aefb0aedb01210387947b950113f035a5ffc732912670ebb34db4a97f6e3dd4ada2205b3994a2340247304402204d1f7ba9de4889c9af06988de1142079f0f59ee3296b7acc5bb17cdda415260702200599898d448ee0798e9ced9eef059fc41d2a3c34b8526597d92655f64d6deacb01210387947b950113f035a5ffc732912670ebb34db4a97f6e3dd4ada2205b3994a23400000000" }