UNPKG

bitcore-node

Version:

A blockchain indexing node with extended capabilities using bitcore

311 lines 14.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const bson_1 = require("bson"); const chai_1 = require("chai"); const sinon = __importStar(require("sinon")); const request_1 = __importDefault(require("request")); const walletAddress_1 = require("../../../src/models/walletAddress"); const csp_1 = require("../../../src/modules/ripple/api/csp"); const block_1 = require("../../../src/modules/ripple/models/block"); const transaction_1 = require("../../../src/modules/ripple/models/transaction"); const rippletxs_fixture_1 = require("../../fixtures/rippletxs.fixture"); const helpers_1 = require("../../helpers"); const integration_1 = require("../../helpers/integration"); describe('Ripple Api', function () { const suite = this; const network = 'testnet'; this.timeout(30000); before(integration_1.intBeforeHelper); after(async () => { await (0, integration_1.intAfterHelper)(suite); const client = await csp_1.XRP.getClient(network); client.rpc.disconnect(); }); beforeEach(async () => { await (0, helpers_1.resetDatabase)(); }); it('should be able to get the ledger', async () => { const client = await csp_1.XRP.getClient(network); const { ledger } = await client.getBlock(); (0, chai_1.expect)(ledger).to.exist; (0, chai_1.expect)(ledger.ledger_hash).to.exist; }); it('should be able to get local tip', async () => { const chain = 'XRP'; await block_1.XrpBlockStorage.collection.insertOne({ chain, network, height: 5, hash: '528f01c17829622ed6a4af51b3b3f6c062f304fa60e66499c9cbb8622c8407f7', time: new Date(1526326784), timeNormalized: new Date(1526326784), transactionCount: 1, reward: 50, previousBlockHash: '64bfb3eda276ae4ae5b64d9e36c9c0b629bc767fb7ae66f9d55d2c5c8103a929', nextBlockHash: '', size: 264, processed: true }); const tip = await csp_1.XRP.getLocalTip({ chain, network }); (0, chai_1.expect)(tip).to.exist; (0, chai_1.expect)(tip.hash).to.exist; (0, chai_1.expect)(tip.hash).to.eq('528f01c17829622ed6a4af51b3b3f6c062f304fa60e66499c9cbb8622c8407f7'); }); for (const tx of rippletxs_fixture_1.RippleTxs) { it('should transform a ripple rpc response into a bitcore transaction: ' + tx.hash, async () => { const bitcoreTx = await csp_1.XRP.transform(tx, 'testnet'); (0, chai_1.expect)(bitcoreTx).to.have.property('chain'); (0, chai_1.expect)(tx.Account).to.eq(bitcoreTx.from); (0, chai_1.expect)(tx.ledger_index).to.eq(bitcoreTx.blockHeight); (0, chai_1.expect)(tx.Fee).to.eq((bitcoreTx.fee).toString()); const nodes = tx.meta.AffectedNodes.filter(node => 'ModifiedNode' in node && node.ModifiedNode.FinalFields?.Account == tx.Account); const sentVal = nodes.reduce((acc, node) => acc += 'ModifiedNode' in node ? Number(node.ModifiedNode.FinalFields?.Balance) - Number(node.ModifiedNode.PreviousFields?.Balance) : 0, 0); (0, chai_1.expect)(sentVal).to.be.lt(0); if (tx.meta.delivered_amount) { const modNodes = tx.meta.AffectedNodes.filter(n => 'ModifiedNode' in n && n.ModifiedNode.FinalFields?.Account === bitcoreTx.to); const createNodes = tx.meta.AffectedNodes.filter(n => 'CreatedNode' in n && n.CreatedNode.NewFields.Account === bitcoreTx.to); (0, chai_1.expect)(modNodes.length + createNodes.length > 0).to.equal(true); (0, chai_1.expect)(tx.meta.delivered_amount).to.eq(bitcoreTx.value.toString()); let receivedVal = modNodes.reduce((acc, node) => acc += 'ModifiedNode' in node ? Number(node.ModifiedNode.FinalFields?.Balance) - Number(node.ModifiedNode.PreviousFields?.Balance) : 0, 0); receivedVal += createNodes.reduce((acc, node) => acc += 'CreatedNode' in node ? Number(node.CreatedNode.NewFields.Balance) : 0, 0); (0, chai_1.expect)(receivedVal).to.be.gt(0); } }); } it('should tag txs from a wallet', async () => { const chain = 'XRP'; const network = 'testnet'; const wallet = new bson_1.ObjectId(); const address = 'rN33DVnneYUUgTmcxXnXvgAL1BECuLZ8pm'; await walletAddress_1.WalletAddressStorage.collection.insertOne({ chain, network, wallet, address, processed: true }); for (const tx of rippletxs_fixture_1.RippleTxs) { const bitcoreTx = (await csp_1.XRP.transform(tx, network)); const bitcoreCoins = csp_1.XRP.transformToCoins(tx, network); const { transaction, coins } = await csp_1.XRP.tag(chain, network, bitcoreTx, bitcoreCoins); (0, chai_1.expect)(transaction.wallets.length).eq(1); (0, chai_1.expect)(transaction.wallets[0].equals(wallet)); let hasACoin = false; for (const coin of coins) { if (coin.address == address) { hasACoin = true; (0, chai_1.expect)(coin.wallets.length).eq(1); (0, chai_1.expect)(coin.wallets[0].equals(wallet)); } } (0, chai_1.expect)(hasACoin).eq(true); } }); it('should get sequence', async () => { const sequence = await csp_1.XRP.getAccountNonce(network, 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'); (0, chai_1.expect)(sequence).to.exist; (0, chai_1.expect)(sequence).to.be.a('number'); }); it('should get flags', async () => { const flags = await csp_1.XRP.getAccountFlags(network, 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'); (0, chai_1.expect)(flags).to.exist; (0, chai_1.expect)(flags).to.haveOwnProperty('requireDestinationTag'); }); it('should save tagged transactions to the database', async () => { const chain = 'XRP'; const network = 'testnet'; const wallet = new bson_1.ObjectId(); const address = 'rN33DVnneYUUgTmcxXnXvgAL1BECuLZ8pm'; await walletAddress_1.WalletAddressStorage.collection.insertOne({ chain, network, wallet, address, processed: true }); const blockTxs = new Array(); const blockCoins = new Array(); for (const tx of rippletxs_fixture_1.RippleTxs) { const bitcoreTx = csp_1.XRP.transform(tx, network); const bitcoreCoins = csp_1.XRP.transformToCoins(tx, network); const { transaction, coins } = await csp_1.XRP.tag(chain, network, bitcoreTx, bitcoreCoins); blockTxs.push(transaction); blockCoins.push(...coins); } await transaction_1.XrpTransactionStorage.batchImport({ txs: blockTxs, coins: blockCoins, chain, network, initialSyncComplete: false }); const walletTxs = await transaction_1.XrpTransactionStorage.collection.find({ chain, network, wallets: wallet }).toArray(); (0, chai_1.expect)(walletTxs.length).eq(rippletxs_fixture_1.RippleTxs.length); }); describe('getBlockBeforeTime', () => { // For these tests, we simulate ledgers with a 1 second interval, so the close_time is xrpEpoch + (ledger_index * 1000) const xrpEpoch = new Date('2000-01-01T00:00:00.000Z'); const getCloseTime = (ledgerIndex) => new Date(xrpEpoch.getTime() + (ledgerIndex * 1000)); const sandbox = sinon.createSandbox(); let requestStub; let validBody = { result: { status: 'success', ledger: { ledger_hash: 'abc123', ledger_index: 12, parent_hash: 'abc122', close_time: getCloseTime(12).getTime() / 1000, close_time_human: getCloseTime(12).toUTCString(), closed: true } } }; let invalidBody = { result: { status: 'error' } }; let time; const _configBak = csp_1.XRP.config; before(async () => { await block_1.XrpBlockStorage.collection.deleteMany({}); }); beforeEach(async () => { requestStub = sandbox.stub(request_1.default, 'post'); await block_1.XrpBlockStorage.collection.insertMany([{ chain: 'XRP', network: 'testnet', height: 12, timeNormalized: getCloseTime(12), hash: 'abc123', time: getCloseTime(12), transactionCount: 1, reward: 50, previousBlockHash: 'abc122', nextBlockHash: 'abc124', size: 264, processed: true }, { chain: 'XRP', network: 'testnet', height: 13, timeNormalized: getCloseTime(13), hash: 'abc124', time: getCloseTime(13), transactionCount: 1, reward: 50, previousBlockHash: 'abc123', nextBlockHash: '', size: 264, processed: true }]); time = getCloseTime(12).toISOString(); }); afterEach(async () => { sandbox.restore(); await block_1.XrpBlockStorage.collection.deleteMany({}); csp_1.XRP.config = _configBak; }); it('should return block', async () => { requestStub.callsFake(function (req, cb) { validBody.result.ledger.ledger_index = req.body.params[0].ledger_index; validBody.result.ledger.close_time = getCloseTime(req.body.params[0].ledger_index).getTime() / 1000; validBody.result.ledger.close_time_human = new Date(validBody.result.ledger.close_time * 1000).toUTCString(); return cb(null, { body: validBody }); }); const res = await csp_1.XRP.getBlockBeforeTime({ chain: 'XRP', network: 'testnet', time }); (0, chai_1.expect)(res).to.deep.equal({ chain: 'XRP', network: 'testnet', hash: 'abc123', height: 12, previousBlockHash: 'abc122', processed: true, time: getCloseTime(12), timeNormalized: getCloseTime(12), reward: 0, size: 0, transactionCount: 0, nextBlockHash: '' }); }); it('should respond null if date is too early', async () => { const res = await csp_1.XRP.getBlockBeforeTime({ chain: 'XRP', network: 'testnet', time: getCloseTime(-1).toISOString() }); (0, chai_1.expect)(res).to.be.null; }); it('should resolve on empty response', async () => { requestStub.callsArgWith(1, null, null); const res = await csp_1.XRP.getBlockBeforeTime({ chain: 'XRP', network: 'testnet', time }); (0, chai_1.expect)(res).to.be.null; }); it('should throw on invalid time', async () => { try { await csp_1.XRP.getBlockBeforeTime({ chain: 'XRP', network: 'testnet', time: 'not-a-time' }); throw new Error('should have thrown'); } catch (err) { (0, chai_1.expect)(err.message).to.equal('Invalid time value'); } }); it('should throw on response error', async () => { requestStub.callsArgWith(1, 'Unresponsive server', validBody); try { await csp_1.XRP.getBlockBeforeTime({ chain: 'XRP', network: 'testnet', time }); throw new Error('should have thrown'); } catch (err) { (0, chai_1.expect)(err).to.equal('Unresponsive server'); } }); it('should return null on error response', async () => { requestStub.callsArgWith(1, null, invalidBody); const res = await csp_1.XRP.getBlockBeforeTime({ chain: 'XRP', network: 'testnet', time }); (0, chai_1.expect)(res).to.be.null; }); it('should throw on mis-configuration', async () => { requestStub.callsArgWith(1, null, validBody); csp_1.XRP.config = {}; try { await csp_1.XRP.getBlockBeforeTime({ chain: 'XRP', network: 'testnet', time }); throw new Error('should have thrown'); } catch (err) { (0, chai_1.expect)(err.message).to.equal('Cannot read properties of undefined (reading \'provider\')'); } }); }); }); //# sourceMappingURL=csp.spec.js.map