diff --git a/test/util/regtest.js b/test/util/regtest.js index dbfc7d79d..12760eea2 100644 --- a/test/util/regtest.js +++ b/test/util/regtest.js @@ -6,6 +6,8 @@ const assert = require('./assert'); const sleep = require('./sleep'); const FullNode = require('../../lib/node/fullnode'); const SPVNode = require('../../lib/node/spvnode'); +const Coin = require('../../lib/primitives/coin'); +const MTX = require('../../lib/primitives/mtx'); async function initFullNode(options) { const node = new FullNode({ @@ -192,6 +194,43 @@ async function generateTxs(options) { return txids; } +async function sendCoinbase(options) { + const { + nclient, + height, + address, + coinbaseKey + } = options; + + const hash = await nclient.execute('getblockhash', [height]); + const block = await nclient.execute('getblock', [hash, true, true]); + + const script = Buffer.from(block.tx[0].vout[0].scriptPubKey.hex, 'hex'); + const prevhash = Buffer.from(block.tx[0].hash, 'hex'); + prevhash.reverse(); + + const mtx = new MTX(); + + mtx.addCoin(Coin.fromOptions({ + value: 5000000000, + script: script, + hash: prevhash, + index: 0 + })); + + mtx.addOutput({ + address: address, + value: 4999000000 + }); + + mtx.sign(coinbaseKey); + + const tx = mtx.toTX(); + + const result = await nclient.execute('sendrawtransaction', + [tx.toRaw().toString('hex')]); +} + async function generateInitialBlocks(options) { const { nclient, @@ -261,4 +300,5 @@ module.exports = { generateReorg, generateRollback, generateTxs, + sendCoinbase } diff --git a/test/wallet-http-test.js b/test/wallet-http-test.js index 37112460b..fefec5d7d 100644 --- a/test/wallet-http-test.js +++ b/test/wallet-http-test.js @@ -79,7 +79,7 @@ describe('Wallet TX HTTP Pagination', function() { unconfirmedTime = new Date(); // Generate unconfirmed transactions for the - // fullnode wallet + // fullnode and spv wallet const txids = await generateTxs({ wclient, spvwclient, diff --git a/test/wallet-rescan-test.js b/test/wallet-rescan-test.js new file mode 100644 index 000000000..da23c64ff --- /dev/null +++ b/test/wallet-rescan-test.js @@ -0,0 +1,182 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + +'use strict'; + +const path = require('path'); +const assert = require('./util/assert'); +const rimraf = require('./util/rimraf'); +const sleep = require('./util/sleep'); +const KeyRing = require('../lib/primitives/keyring'); + +const { + initFullNode, + initSPVNode, + initNodeClient, + initWalletClient, + initWallet, + generateInitialBlocks, + generateBlocks, + generateReorg, + generateTxs, + sendCoinbase +} = require('./util/regtest'); + +const testPrefix = '/tmp/bcoin-fullnode'; +const spvTestPrefix = '/tmp/bcoin-spvnode'; +const genesisTime = 1534965859; +const genesisDate = new Date(genesisTime * 1000); + +const ports = { + full: { + p2p: 49331, + node: 49332, + wallet: 49333 + }, + spv: { + p2p: 49431, + node: 49432, + wallet: 49433 + } +} + +describe('Wallet Rescan', function() { + this.timeout(30000); + + let node, spvnode, wallet, spvwallet = null; + let nclient, wclient, spvwclient = null; + let coinbase, coinbaseKey = null; + let fulladdr, spvaddr = null; + let key1, key2, key3 = null; + + before(async () => { + await rimraf(testPrefix); + await rimraf(spvTestPrefix); + + node = await initFullNode({ports, prefix: testPrefix, logLevel: 'none'}); + spvnode = await initSPVNode({ports, prefix: spvTestPrefix, logLevel: 'none'}); + + nclient = await initNodeClient({ports: ports.full}); + wclient = await initWalletClient({ports: ports.full}); + spvwclient = await initWalletClient({ports: ports.spv}); + wallet = await initWallet(wclient); + spvwallet = await initWallet(spvwclient); + + coinbaseKey = KeyRing.generate(); + + await wclient.execute('selectwallet', ['test']); + await spvwclient.execute('selectwallet', ['test']); + + fulladdr = await wclient.execute('getnewaddress', ['blue']); + spvaddr = await spvwclient.execute('getnewaddress', ['blue']); + + // Use coinbase outside of any wallet so + // that we can send funds to various addresses + // without affecting the wallets. + coinbase = coinbaseKey.getAddress('base58', 'regtest').toString(); + + await generateInitialBlocks({ + nclient, + coinbase, + genesisTime, + blocks: 200 + }); + + // TODO remove this + await sleep(5000); + + const count = await wclient.execute('listhistorycount', ['blue']); + assert.strictEqual(count, 0); + + key1 = KeyRing.generate(); + key2 = KeyRing.generate(); + key3 = KeyRing.generate(); + + let height = 0; + + // Send funds to the existing wallets + await sendCoinbase({ + nclient, + height: ++height, + coinbaseKey, + address: fulladdr + }); + + await sendCoinbase({ + nclient, + height: ++height, + coinbaseKey, + address: spvaddr + }); + + await generateBlocks(1, nclient, coinbase); + + // Send funds to the addresses to be imported + for (++height; height < 13; height++) { + const address = key1.getAddress('base58', 'regtest').toString(); + await sendCoinbase({ + nclient, + height, + coinbaseKey, + address + }); + } + + await generateBlocks(1, nclient, coinbase); + + // Send more funds to the wallets after the + // addresses to be imported + await sendCoinbase({ + nclient, + height: ++height, + coinbaseKey, + address: fulladdr + }); + + await sendCoinbase({ + nclient, + height: ++height, + coinbaseKey, + address: spvaddr + }); + + await generateBlocks(1, nclient, coinbase); + + // Import keys into wallets and rescan + const key1Priv = key1.getPrivateKey('base58', 'regtest'); + await wclient.execute('importprivkey', [key1Priv, null, true]); + await spvwclient.execute('importprivkey', [key1Priv, null, true]); + + // TODO remove this + await sleep(5000); + }); + + after(async () => { + await wallet.close(); + await wclient.close(); + await spvwclient.close(); + await nclient.close(); + await node.close(); + await spvnode.close(); + }); + + describe('full node wallet', function() { + it('has the correct number of txs', async () => { + const count = await wclient.execute('listhistorycount', ['blue']); + assert.strictEqual(count, 14); + }); + + it('wallet should include txs of imported addresses', async () => { + }); + }); + + describe('spv node wallet', function() { + it('has the correct number of txs', async () => { + const count = await spvwclient.execute('listhistorycount', ['blue']); + assert.strictEqual(count, 14); + }); + + it('wallet should include txs of imported addresses', async () => { + }); + }); +});