From 7bb3741fa9d847e8d39f9e7f7d99b6d8908ee41a Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 16 Apr 2020 18:37:57 -0700 Subject: [PATCH] fix(ElectrumX): get methods for balance, utxos, and tx history compelte --- src/routes/v3/electrumx.js | 39 ++++++++++++++-- test/v3/a01-electrumx.js | 82 ++++++++++++++++++++++++++++++++- test/v3/mocks/electrumx-mock.js | 10 +++- 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/routes/v3/electrumx.js b/src/routes/v3/electrumx.js index bcacb69..9cdb111 100644 --- a/src/routes/v3/electrumx.js +++ b/src/routes/v3/electrumx.js @@ -268,9 +268,9 @@ class Electrum { 'blockchain.scripthash.get_balance', scripthash ) - console.log( - `electrumResponse: ${JSON.stringify(electrumResponse, null, 2)}` - ) + // console.log( + // `electrumResponse: ${JSON.stringify(electrumResponse, null, 2)}` + // ) return electrumResponse } catch (err) { @@ -281,6 +281,39 @@ class Electrum { throw err } } + + // Returns a promise that resolves an array of transaction history for an + // address. Expects input to be a cash address, and input validation to have + // already been done by parent, calling function. + async _transactionsFromElectrumx (address) { + try { + // Convert the address to a scripthash. + const scripthash = _this.addressToScripthash(address) + + if (!_this.isReady) { + throw new Error( + 'ElectrumX server connection is not ready. Call await connectToServer() first.' + ) + } + + // Query the address transaction history from the ElectrumX server. + const electrumResponse = await _this.electrumx.request( + 'blockchain.scripthash.get_history', + scripthash + ) + // console.log( + // `electrumResponse: ${JSON.stringify(electrumResponse, null, 2)}` + // ) + + return electrumResponse + } catch (err) { + // console.log('err1: ', err) + + // Write out error to error log. + wlogger.error('Error in elecrumx.js/_transactionsFromElectrumx(): ', err) + throw err + } + } } module.exports = Electrum diff --git a/test/v3/a01-electrumx.js b/test/v3/a01-electrumx.js index 9529d22..eb6c984 100644 --- a/test/v3/a01-electrumx.js +++ b/test/v3/a01-electrumx.js @@ -255,7 +255,7 @@ describe('#ElectrumX Router', () => { }) it('should get balance for a single address', async () => { - const address = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' + const address = 'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7' // Mock unit tests to prevent live network calls. if (process.env.TEST === 'unit') { @@ -304,7 +304,27 @@ describe('#ElectrumX Router', () => { }) it('should get balance for a single address', async () => { - const address = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' + const address = 'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7' + + // Mock unit tests to prevent live network calls. + if (process.env.TEST === 'unit') { + electrumxRoute.isReady = true // Force flag. + + sandbox + .stub(electrumxRoute.electrumx, 'request') + .resolves(mockData.balance) + } + + // Call the details API. + const result = await electrumxRoute._balanceFromElectrumx(address) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.property(result, 'confirmed') + assert.property(result, 'unconfirmed') + }) + + it('should get balance for an address with no transaction history', async () => { + const address = 'bitcoincash:qp2ew6pvrs22jtsvtjyumjgas6jkvgn2hy3ad4wpw8' // Mock unit tests to prevent live network calls. if (process.env.TEST === 'unit') { @@ -323,4 +343,62 @@ describe('#ElectrumX Router', () => { assert.property(result, 'unconfirmed') }) }) + + describe('#_transactionsFromElectrumx', () => { + it('should throw error for invalid address', async () => { + try { + // Address has invalid checksum. + const address = 'bitcoincash:qr69kyzha07dcecrsvjwsj4s6slnlq4r8c30lxnur2' + + // Call the details API. + await electrumxRoute._transactionsFromElectrumx(address) + + assert.equal(true, false, 'Unexpected code path') + } catch (err) { + // console.log('err2: ', err) + assert.include(err.message, 'Invalid checksum') + } + }) + + it('should get transaction history for a single address', async () => { + const address = 'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7' + + // Mock unit tests to prevent live network calls. + if (process.env.TEST === 'unit') { + electrumxRoute.isReady = true // Force flag. + + sandbox + .stub(electrumxRoute.electrumx, 'request') + .resolves(mockData.txHistory) + } + + // Call the details API. + const result = await electrumxRoute._transactionsFromElectrumx(address) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.property(result[0], 'height') + assert.property(result[0], 'tx_hash') + }) + + it('should get history for an address with no transaction history', async () => { + const address = 'bitcoincash:qp2ew6pvrs22jtsvtjyumjgas6jkvgn2hy3ad4wpw8' + + // Mock unit tests to prevent live network calls. + if (process.env.TEST === 'unit') { + electrumxRoute.isReady = true // Force flag. + + sandbox + .stub(electrumxRoute.electrumx, 'request') + .resolves([]) + } + + // Call the details API. + const result = await electrumxRoute._transactionsFromElectrumx(address) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.equal(result.length, 0) + }) + }) }) diff --git a/test/v3/mocks/electrumx-mock.js b/test/v3/mocks/electrumx-mock.js index 067c83f..65baf09 100644 --- a/test/v3/mocks/electrumx-mock.js +++ b/test/v3/mocks/electrumx-mock.js @@ -24,7 +24,15 @@ const balance = { unconfirmed: 0 } +const txHistory = [ + { + height: 601861, + tx_hash: '6181c669614fa18039a19b23eb06806bfece1f7514ab457c3bb82a40fe171a6d' + } +] + module.exports = { utxos, - balance + balance, + txHistory }