diff --git a/src/api/common/validate.js b/src/api/common/validate.js index e217007e..b15dd4d1 100644 --- a/src/api/common/validate.js +++ b/src/api/common/validate.js @@ -16,9 +16,7 @@ function validateAddressAndSecret(obj) { throw error('Parameter missing: secret'); } try { - if (!core.Seed.from_json(secret).get_key(address)) { - throw error('secret does not match address'); - } + core.Seed.from_json(secret).get_key(address); } catch (exception) { throw error('secret does not match address'); } diff --git a/test/api-test.js b/test/api-test.js index 1c11708c..fd56b889 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -12,7 +12,8 @@ const hashes = require('./fixtures/hashes'); const MockPRNG = require('./mock-prng'); const sjcl = require('../src').sjcl; const address = addresses.ACCOUNT; -const validate = require('../src/api/common/validate'); +const common = require('../src/api/common'); +const validate = common.validate; const RippleError = require('../src/core/rippleerror').RippleError; const utils = require('../src/api/ledger/utils'); const ledgerClosed = require('./fixtures/api/rippled/ledger-close-newer'); @@ -207,6 +208,23 @@ describe('RippleAPI', function() { 'getTransaction', done)); }); + it('getTransaction - trustline frozen off', function(done) { + const hash = + 'FE72FAD0FA7CA904FB6C633A1666EDF0B9C73B2F5A4555D37EEF2739A78A531B'; + this.api.getTransaction(hash, {}, + _.partial(checkResult, responses.getTransaction.trustlineFrozenOff, + 'getTransaction', done)); + }); + + it('getTransaction - not validated', function(done) { + const hash = + '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA10'; + this.api.getTransaction(hash, {}, (error, data) => { + assert.deepEqual(data, responses.getTransaction.notValidated); + done(error); + }); + }); + it('getTransaction - tracking on', function(done) { const hash = '8925FC8844A1E930E2CC76AD0A15E7665AFCC5425376D548BB1413F484C31B8C'; @@ -612,35 +630,110 @@ describe('RippleAPI', function() { }); - it('validator', function() { - const noSecret = {address: address}; - assert.throws(_.partial(validate.addressAndSecret, noSecret), - this.api.errors.ValidationError); - assert.throws(_.partial(validate.addressAndSecret, noSecret), - /Parameter missing/); - const badSecret = {address: address, secret: 'bad'}; - assert.throws(_.partial(validate.addressAndSecret, badSecret), - this.api.errors.ValidationError); - assert.throws(_.partial(validate.addressAndSecret, badSecret), - /not match/); - const goodWallet = {address: 'rpZMK8hwyrBvLorFNWHRCGt88nCJWbixur', - secret: 'shzjfakiK79YQdMjy4h8cGGfQSV6u' - }; - assert.doesNotThrow(_.partial(validate.addressAndSecret, goodWallet)); - assert.doesNotThrow(_.partial(validate.secret, - 'shzjfakiK79YQdMjy4h8cGGfQSV6u')); - assert.throws(_.partial(validate.secret, 1), - /Invalid parameter/); - assert.throws(_.partial(validate.secret, ''), - this.api.errors.ValidationError); - assert.throws(_.partial(validate.secret, 's!!!'), - this.api.errors.ValidationError); - assert.throws(_.partial(validate.secret, 'passphrase'), - this.api.errors.ValidationError); - // 32 0s is a valid hex repr of seed bytes - const hex = new Array(33).join('0'); - assert.throws(_.partial(validate.secret, hex), - this.api.errors.ValidationError); + describe('validator', function() { + + it('validateLedgerRange', function() { + const options = { + minLedgerVersion: 20000, + maxLedgerVersion: 10000 + }; + assert.throws(_.partial(validate.getTransactionsOptions, options), + this.api.errors.ValidationError); + assert.throws(_.partial(validate.getTransactionsOptions, options), + /minLedgerVersion must not be greater than maxLedgerVersion/); + }); + + it('addressAndSecret', function() { + const wrongSecret = {address: address, + secret: 'shzjfakiK79YQdMjy4h8cGGfQSV6u' + }; + assert.throws(_.partial(validate.addressAndSecret, wrongSecret), + this.api.errors.ValidationError); + const noSecret = {address: address}; + assert.throws(_.partial(validate.addressAndSecret, noSecret), + this.api.errors.ValidationError); + assert.throws(_.partial(validate.addressAndSecret, noSecret), + /Parameter missing/); + const badSecret = {address: address, secret: 'bad'}; + assert.throws(_.partial(validate.addressAndSecret, badSecret), + this.api.errors.ValidationError); + assert.throws(_.partial(validate.addressAndSecret, badSecret), + /not match/); + const goodWallet = {address: 'rpZMK8hwyrBvLorFNWHRCGt88nCJWbixur', + secret: 'shzjfakiK79YQdMjy4h8cGGfQSV6u' + }; + assert.doesNotThrow(_.partial(validate.addressAndSecret, goodWallet)); + }); + + it('secret', function() { + assert.doesNotThrow(_.partial(validate.secret, + 'shzjfakiK79YQdMjy4h8cGGfQSV6u')); + assert.throws(_.partial(validate.secret, 1), + /Invalid parameter/); + assert.throws(_.partial(validate.secret, ''), + this.api.errors.ValidationError); + assert.throws(_.partial(validate.secret, 's!!!'), + this.api.errors.ValidationError); + assert.throws(_.partial(validate.secret, 'passphrase'), + this.api.errors.ValidationError); + // 32 0s is a valid hex repr of seed bytes + const hex = new Array(33).join('0'); + assert.throws(_.partial(validate.secret, hex), + this.api.errors.ValidationError); + }); + + }); + + describe('common utils', function() { + + it('wrapCatch', function(done) { + common.wrapCatch(function() { + throw new Error('error'); + })(function(error) { + assert(error instanceof Error); + done(); + }); + }); + + it('convertExceptions', function() { + assert.throws(common.convertExceptions(function() { + throw new Error('fall through'); + }), this.api.errors.ApiError); + assert.throws(common.convertExceptions(function() { + throw new Error('fall through'); + }), /fall through/); + }); + + }); + + describe('common errors', function() { + + it('TransactionError', function() { + // TransactionError is not used anywhere, so just test its creation + assert.throws(function() { + throw new common.errors.TransactionError('fall through'); + }, this.api.errors.TransactionError); + assert.throws(function() { + throw new common.errors.TransactionError('fall through'); + }, /fall through/); + }); + + it('TimeOutError', function() { + // TimeOutError is not used anywhere, so just test its creation + assert.throws(function() { + throw new common.errors.TimeOutError('fall through'); + }, this.api.errors.TimeOutError); + assert.throws(function() { + throw new common.errors.TimeOutError('fall through'); + }, /fall through/); + }); + + it('RippledNetworkError', function() { + assert.throws(function() { + throw new common.errors.RippledNetworkError(); + }, /Cannot connect to rippled/); + }); + }); }); diff --git a/test/fixtures/api/responses/get-transaction-not-validated.json b/test/fixtures/api/responses/get-transaction-not-validated.json new file mode 100644 index 00000000..65b24330 --- /dev/null +++ b/test/fixtures/api/responses/get-transaction-not-validated.json @@ -0,0 +1,11 @@ +{ + "type": "settings", + "address": "rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe", + "sequence": 1, + "id": "4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA10", + "specification": { + "requireAuthorization": true, + "disallowIncomingXRP": true, + "globalFreeze": false + } +} diff --git a/test/fixtures/api/responses/get-transaction-trust-set-frozen-off.json b/test/fixtures/api/responses/get-transaction-trust-set-frozen-off.json new file mode 100644 index 00000000..cc5210d8 --- /dev/null +++ b/test/fixtures/api/responses/get-transaction-trust-set-frozen-off.json @@ -0,0 +1,31 @@ +{ + "type": "trustline", + "address": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b", + "sequence": 478, + "id": "FE72FAD0FA7CA904FB6C633A1666EDF0B9C73B2F5A4555D37EEF2739A78A531B", + "specification": { + "limit": "10000", + "currency": "USD", + "counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM", + "qualityIn": 0.91, + "qualityOut": 0.87, + "ripplingDisabled": true, + "frozen": false + }, + "outcome": { + "result": "tesSUCCESS", + "timestamp": "2015-07-29T12:33:30.000Z", + "fee": "0.012", + "balanceChanges": { + "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b": [ + { + "currency": "XRP", + "value": "-0.012" + } + ] + }, + "orderbookChanges": {}, + "ledgerVersion": 14930204, + "indexInLedger": 3 + } +} diff --git a/test/fixtures/api/responses/index.js b/test/fixtures/api/responses/index.js index 507d10a2..15efa03d 100644 --- a/test/fixtures/api/responses/index.js +++ b/test/fixtures/api/responses/index.js @@ -21,7 +21,9 @@ module.exports = { trustline: require('./get-transaction-trustline-set.json'), trackingOn: require('./get-transaction-settings-tracking-on.json'), trackingOff: require('./get-transaction-settings-tracking-off.json'), - setRegularKey: require('./get-transaction-settings-set-regular-key.json') + setRegularKey: require('./get-transaction-settings-set-regular-key.json'), + trustlineFrozenOff: require('./get-transaction-trust-set-frozen-off.json'), + notValidated: require('./get-transaction-not-validated.json') }, getTransactions: require('./get-transactions.json'), getTrustlines: require('./get-trustlines.json'), diff --git a/test/fixtures/api/rippled/index.js b/test/fixtures/api/rippled/index.js index ded71e45..714318ee 100644 --- a/test/fixtures/api/rippled/index.js +++ b/test/fixtures/api/rippled/index.js @@ -30,9 +30,11 @@ module.exports = { OfferCreate: require('./tx/offer-create.json'), OfferCancel: require('./tx/offer-cancel.json'), TrustSet: require('./tx/trust-set.json'), + TrustSetFrozenOff: require('./tx/trust-set-frozen-off.json'), NotFound: require('./tx/not-found.json'), NoLedgerIndex: require('./tx/no-ledger-index.json'), NoLedgerFound: require('./tx/no-ledger-found.json'), - LedgerWithoutTime: require('./tx/ledger-without-time.json') + LedgerWithoutTime: require('./tx/ledger-without-time.json'), + NotValidated: require('./tx/not-validated.json') } }; diff --git a/test/fixtures/api/rippled/tx/not-validated.json b/test/fixtures/api/rippled/tx/not-validated.json new file mode 100644 index 00000000..aba33004 --- /dev/null +++ b/test/fixtures/api/rippled/tx/not-validated.json @@ -0,0 +1,45 @@ +{ + "id": 0, + "status": "success", + "type": "response", + "result": { + "Account": "rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe", + "Fee": "10", + "Flags": 2147483648, + "Sequence": 1, + "SetFlag": 2, + "SigningPubKey": "03EA3ADCA632F125EC2CC4F7F6A82DE0DCE2B65290CAC1F22242C5163F0DA9652D", + "TransactionType": "AccountSet", + "TxnSignature": "3045022100DE8B666B1A31EA65011B0F32130AB91A5747E32FA49B3054CEE8E8362DBAB98A022040CF0CF254677A8E5CD04C59CA2ED7F6F15F7E184641BAE169C561650967B226", + "date": 460832270, + "hash": "4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA10", + "inLedger": 8206418, + "ledger_index": 8206418, + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "Account": "rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe", + "Balance": "29999990", + "Flags": 786432, + "OwnerCount": 0, + "Sequence": 2 + }, + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "3F5072C4875F32ED770DAF3610A716600ED7C7BB0348FADC7A98E011BB2CD36F", + "PreviousFields": { + "Balance": "30000000", + "Flags": 4194304, + "Sequence": 1 + }, + "PreviousTxnID": "3FB0350A3742BBCC0D8AA3C5247D1AEC01177D0A24D9C34762BAA2FEA8AD88B3", + "PreviousTxnLgrSeq": 8206397 + } + } + ], + "TransactionIndex": 5, + "TransactionResult": "tesSUCCESS" + } + } +} diff --git a/test/fixtures/api/rippled/tx/trust-set-frozen-off.json b/test/fixtures/api/rippled/tx/trust-set-frozen-off.json new file mode 100644 index 00000000..99fe993e --- /dev/null +++ b/test/fixtures/api/rippled/tx/trust-set-frozen-off.json @@ -0,0 +1,87 @@ +{ + "id": 0, + "result": { + "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b", + "Fee": "12000", + "Flags": 2228224, + "LastLedgerSequence": 14930302, + "LimitAmount": { + "currency": "USD", + "issuer": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM", + "value": "10000" + }, + "QualityIn": 910000000, + "QualityOut": 870000000, + "Sequence": 478, + "SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025", + "TransactionType": "TrustSet", + "TxnSignature": "3045022100EFC7E29D20C108CDFF6B825EB363923F25A92BFE7858466D82ECE5D578F5DFAD022035CEBF2DB99E70A0088B03037FA0F63BB2DAE33C8C48F7FF43B6AF112EE16121", + "date": 491488410, + "hash": "FE72FAD0FA7CA904FB6C633A1666EDF0B9C73B2F5A4555D37EEF2739A78A531B", + "inLedger": 14930204, + "ledger_index": 14930204, + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "Balance": { + "currency": "USD", + "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji", + "value": "0" + }, + "Flags": 3211264, + "HighLimit": { + "currency": "USD", + "issuer": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM", + "value": "0" + }, + "HighNode": "0000000000000000", + "LowLimit": { + "currency": "USD", + "issuer": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b", + "value": "10000" + }, + "LowNode": "0000000000000000", + "LowQualityIn": 910000000, + "LowQualityOut": 870000000 + }, + "LedgerEntryType": "RippleState", + "LedgerIndex": "072DF69CEE470A944D39E9994C335154504CFCB8B706C4E49199E1F8FB70828E", + "PreviousFields": { + "Flags": 7405568 + }, + "PreviousTxnID": "5ADB0B380834BB75506078422802175B6F54FD28FB7CE0C83F369C805EB4BF36", + "PreviousTxnLgrSeq": 14930185 + } + }, + { + "ModifiedNode": { + "FinalFields": { + "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b", + "Balance": "71671088", + "Domain": "726970706C652E636F6D", + "Flags": 65536, + "OwnerCount": 3, + "RegularKey": "rsvEdWvfwzqkgvmaSEh9kgbcWiUc6s69ZC", + "Sequence": 479 + }, + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9", + "PreviousFields": { + "Balance": "71683088", + "Sequence": 478 + }, + "PreviousTxnID": "5ADB0B380834BB75506078422802175B6F54FD28FB7CE0C83F369C805EB4BF36", + "PreviousTxnLgrSeq": 14930185 + } + } + ], + "TransactionIndex": 3, + "TransactionResult": "tesSUCCESS" + }, + "validated": true + }, + "status": "success", + "type": "response" +} diff --git a/test/mock-rippled.js b/test/mock-rippled.js index fa41253a..a6d95335 100644 --- a/test/mock-rippled.js +++ b/test/mock-rippled.js @@ -158,6 +158,12 @@ module.exports = function(port) { } else if (request.transaction === '0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A04') { conn.send(createResponse(request, fixtures.tx.LedgerWithoutTime)); + } else if (request.transaction === + 'FE72FAD0FA7CA904FB6C633A1666EDF0B9C73B2F5A4555D37EEF2739A78A531B') { + conn.send(createResponse(request, fixtures.tx.TrustSetFrozenOff)); + } else if (request.transaction === + '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA10') { + conn.send(createResponse(request, fixtures.tx.NotValidated)); } else if (request.transaction === hashes.NOTFOUND_TRANSACTION_HASH) { conn.send(createResponse(request, fixtures.tx.NotFound)); } else {