UNPKG

gitiumiota

Version:
406 lines (378 loc) 13.1 kB
import { CDA } from '@iota/cda' import { trytesToTrits } from '@iota/converter' import { generateAddress } from '@iota/core' import * as BluebirdPromise from 'bluebird' import * as nock from 'nock' import { describe } from 'riteway' import { IRICommand } from '../../types' import { createAccount, createAccountWithPreset } from '../src/account' import { preset } from '../src/preset' import { accountASends10iToB as accountASends10iToBTrytes, accountASpendsFromRemainder as accountASpendsFromRemainderTrytes, } from './trytes' const persistencePath = './test/temp' const currentTime = Math.floor(Date.now() / 1000) const futureTime = 6833278800 const pastTime = currentTime - 7 * 24 * 60 * 60 * 1000 const delay = (t: number) => new Promise(resolve => setTimeout(resolve, t)) const headers = { reqheaders: { 'Content-Type': 'application/json', 'X-IOTA-API-Version': '1', }, } describe('account.generateCDA()', async assert => { const accountParams = { seed: trytesToTrits('RQMMPLNFUUCULIIHEYKYBUXUFEDPKTXDQQQRUOBUVIVWIOAXDPNHLAJDSPCXKJNPTPJYBBCJKPVMONYDK'), persistencePath, emitTransferEvents: false, } const account = createAccount(accountParams) assert({ given: 'timeoutAt, multiUse & expectedAmount conditions', should: 'throw error', actual: await (async () => { try { await account.generateCDA({ timeoutAt: futureTime, multiUse: true, expectedAmount: 9, }) } catch (error) { return error.message } })(), expected: 'Only one of the following fields can be set: multiUse, expectedAmount', }) assert({ given: 'timeoutAt & multiUse conditions', should: 'generate 1st CDA', actual: await account.generateCDA({ timeoutAt: futureTime, multiUse: false, }), expected: { address: 'FSPPZHWG9FCUBVTNGMPIUVLMXRUAIWFEXRF9IYHPIYJRIORYOOEDBJN9WBFODDFLAKUOKYFZGDLHZNCXXPZZJZPHFT', timeoutAt: futureTime, multiUse: false, expectedAmount: 0, }, }) assert({ given: 'timeoutAt & expectedAmount conditions', should: 'generate 2nd CDA', actual: await account.generateCDA({ timeoutAt: futureTime, expectedAmount: 9, }), expected: { address: 'KRXPZHNMGVJKBIQXV9ALWFOPGIGNVTJFNVKHSYZLI9AABBHKSPBTKKPRVI9ID9QXXKZGTXSSSBMUQFVLWJYJMXKPRS', timeoutAt: futureTime, multiUse: false, expectedAmount: 9, }, }) assert({ given: 'past time as timeoutAt', should: 'throw "Expired timeout" Error', actual: await (async () => { try { await account.generateCDA({ timeoutAt: pastTime, expectedAmount: 9, }) } catch (error) { return error } })(), expected: new Error('Expired timeout'), }) }) describe('account.generateCDA/account.sendToCDA', async assert => { // --- // account 0 is poor const seed0 = '9'.repeat(81) const address01 = generateAddress(seed0, 1, 2, false) const address01has0Balance = () => { return nock('http://localhost:14265', headers) .post('/', { command: IRICommand.GET_BALANCES, addresses: [address01], threshold: 100, }) .times(1) .reply(200, { balances: [0], milestone: 'M'.repeat(81), milestoneIndex: 1, }) } const account0 = createAccount({ seed: trytesToTrits(seed0), persistencePath, emitTransferEvents: false, timeSource: () => BluebirdPromise.resolve(Math.floor(Date.now() / 1000)), }) // --- // account A has 11i balance in snapshot (A1: 9i + A2: 1i), sends 10i to B, receives remainder of 1i in A3 const seedA = 'RQFLPKU9BIEGPPEIXEHH9RFDUMSYXMPZOVBKBITSPEFMSOIBYHMFVHRNRF9YNZYQRNBYCS9OULYHBFPHZ' const addressA1 = generateAddress(seedA, 1, 2, false) const addressA2 = generateAddress(seedA, 2, 2, false) const addressA3 = generateAddress(seedA, 3, 2, false) const balanceA1 = 9 const balanceA2 = 2 const remainderA3 = 1 const accountA = createAccountWithPreset({ ...preset, test: { now: () => futureTime, }, })({ seed: trytesToTrits(seedA), emitTransferEvents: false, persistencePath, }) const accountARequestedFromAnyInA1 = () => accountA.generateCDA({ timeoutAt: Math.floor(Date.now() / 1000) + 5, multiUse: true, }) const accountARequestedFromAnyInA2 = () => accountA.generateCDA({ timeoutAt: futureTime, expectedAmount: balanceA2, }) const accountAHas9iInA1 = () => nock('http://localhost:14265', headers) .post('/', { command: IRICommand.GET_BALANCES, addresses: [addressA1], threshold: 100, }) .times(1) .reply(200, { balances: [balanceA1], milestone: 'M'.repeat(81), milestoneIndex: 1, }) const accountAHas2iInA2 = () => nock('http://localhost:14265', headers) .post('/', { command: IRICommand.GET_BALANCES, addresses: [addressA2], threshold: 100, }) .times(1) .reply(200, { balances: [balanceA2], milestone: 'M'.repeat(81), milestoneIndex: 1, }) const accountARemainderReceivesExpectedBalance = () => nock('http://localhost:14265', headers) .post('/', { command: IRICommand.GET_BALANCES, addresses: [addressA3], threshold: 100, }) .times(1) .reply(200, { balances: [remainderA3], milestone: 'M'.repeat(81), milestoneIndex: 1, }) // --- // account B requests from 0 and A, receives from A const seedB = 'ZKKZDWNKIWYQHCNTHKAEARYIWUYUBDWVXWWT9FQDOKPNZURMGRFJABUYTLYEQKDVJCNQYKLTVIVSTY9LI' const accountB = createAccountWithPreset({ ...preset, now: () => futureTime, })({ seed: trytesToTrits(seedB), emitTransferEvents: false, persistencePath, }) // request from 0 and A let cdaB1 const accountBRequestsFromAny = () => accountB.generateCDA({ timeoutAt: futureTime, multiUse: true, }) // request 9i from A const accountBRequests10iFromAccountA = () => accountB.generateCDA({ timeoutAt: futureTime, expectedAmount: 10, }) cdaB1 = await accountBRequestsFromAny() const accountASends10iToB = (cda: CDA) => { const hash = 'ZZKVOZRYHZVYORKHDLWRNIWKWLZMVBNFSPQC99PYHVJFRYRHXVUTHPQOVPJBRNFLYWDNKBBUJOTDQVTDE' const transactionsToApprove = { trunkTransaction: '9'.repeat(81), branchTransaction: '9'.repeat(81), } nock('http://localhost:14265', headers) .post('/', { command: IRICommand.FIND_TRANSACTIONS, addresses: [cda.address.slice(0, 81)], }) .times(1) .reply(200, { hashes: [hash], }) nock('http://localhost:14265', headers) .post('/', { command: IRICommand.GET_TRYTES, hashes: [hash], }) .times(1) .reply(200, { trytes: [accountASends10iToBTrytes[0]], }) nock('http://localhost:14265', headers) .persist() .post('/', { command: IRICommand.GET_NODE_INFO }) .reply(200, { appName: 'IRI', appVersion: '', duration: 100, jreAvailableProcessors: 4, jreFreeMemory: 13020403, jreMaxMemory: 1241331231, jreTotalMemory: 4245234332, latestMilestone: 'M'.repeat(81), latestMilestoneIndex: 1, latestSolidSubtangleMilestone: 'M'.repeat(81), latestSolidSubtangleMilestoneIndex: 1, neighbors: 5, packetsQueueSize: 23, time: 213213214, tips: 123, transactionsToRequest: 10, }) nock('http://localhost:14265', headers) .post('/', { command: IRICommand.GET_INCLUSION_STATES, transactions: [hash], tips: ['M'.repeat(81)], }) .times(1) .reply(200, { states: [false], }) nock('http://localhost:14265', headers) .post('/', { command: IRICommand.CHECK_CONSISTENCY, tails: [hash], }) .times(1) .reply(200, { states: [false], }) nock('http://localhost:14265', headers) .post('/', { command: IRICommand.GET_TRANSACTIONS_TO_APPROVE, depth: 3, }) .times(1) .reply(200, { ...transactionsToApprove, }) nock('http://localhost:14265', headers) .post('/', { command: IRICommand.ATTACH_TO_TANGLE, trytes: [...accountASends10iToBTrytes], ...transactionsToApprove, minWeightMagnitude: 9, }) .times(1) .reply(200, { trytes: [...accountASends10iToBTrytes], }) } assert({ given: 'that account0 has 0 persisted CDAs, sendToCDA', should: 'throw "Insufficient balance" error', actual: await (async () => { try { return await account0.sendToCDA({ ...cdaB1, value: 1 }) } catch (error) { return error.message } })(), expected: 'Insufficient balance', }) assert({ given: 'that account0 has 1 persisted, unfunded CDA, sendToCDA', should: 'throw "Insufficient balance" error', actual: await (async () => { try { await address01has0Balance() await account0.generateCDA({ timeoutAt: futureTime, multiUse: true, }) return await account0.sendToCDA({ ...cdaB1, value: 1 }) } catch (error) { return error.message } })(), expected: 'Insufficient balance', }) assert({ given: 'that account A has 11i balance in snapshot (A1: 9i, A2: 2i)', should: 'send 10i to B', actual: await (async () => { try { await accountARequestedFromAnyInA1() await accountARequestedFromAnyInA2() await accountAHas9iInA1() await accountAHas2iInA2() await delay(5500) const cdaB2 = await accountBRequests10iFromAccountA() await accountASends10iToB(cdaB2) return await accountA.sendToCDA({ ...cdaB2, value: cdaB2.expectedAmount, }) } catch (error) { return error.message } })(), expected: accountASends10iToBTrytes, }) assert({ given: 'that previous transfer of 10i to B is included, account A', should: 'be able to spend 1i from remainder address A3', actual: await (async () => { try { await accountARemainderReceivesExpectedBalance() return await accountA.sendToCDA({ ...cdaB1, value: 1, }) } catch (error) { return error.message } })(), expected: accountASpendsFromRemainderTrytes, }) assert({ given: 'that account A has used all inputs in previous transfers, sendToCDA', should: 'throw "insufficient balance" error', actual: await (async () => { try { await accountARemainderReceivesExpectedBalance() return await accountA.sendToCDA({ ...cdaB1, value: 1, }) } catch (error) { return error.message } })(), expected: 'Insufficient balance', }) })