diff --git a/lib/cash-in-tx.js b/lib/cash-in-tx.js index 03cdd095..6eee0b1f 100644 --- a/lib/cash-in-tx.js +++ b/lib/cash-in-tx.js @@ -9,8 +9,6 @@ const mapValuesWithKey = _.mapValues.convert({cap: false}) module.exports = {post, monitorPending} -const UPDATEABLE_FIELDS = ['fee', 'txHash', 'phone', 'error', 'send', - 'cryptoAtoms', 'fiat', 'timedout'] const PENDING_INTERVAL = '1 day' const MAX_PENDING = 10 @@ -43,10 +41,11 @@ function post (tx, pi) { return db.tx(transaction) .then(txVector => { - const [oldTx, newTx, newBills] = txVector + const [oldTx,, newBills] = txVector const oldBills = oldTx ? oldTx.bills : [] + return postProcess(txVector, pi) - .then(changes => update(newTx, changes)) + .then(changes => update(oldTx, changes)) .then(tx => _.merge({bills: _.concat(oldBills, newBills)}, tx)) }) } @@ -57,17 +56,54 @@ function nilEqual (a, b) { return undefined } +function isMonotonic (oldField, newField, fieldKey) { + if (_.isNil(newField)) return false + if (_.isBoolean(oldField)) return oldField === newField || !oldField + if (oldField.isBigNumber) return oldField.lte(newField) + if (_.isNumber(oldField)) return oldField <= newField + + throw new Error(`Unexpected value: ${oldField}`) +} + +function ensureRatchet (oldField, newField, fieldKey) { + const monotonic = ['cryptoAtoms', 'fiat', 'send', 'sendConfirmed', 'operatorCompleted', 'timedout'] + const free = ['sendPending', 'error', 'errorCode'] + + if (_.isNil(oldField)) return true + if (_.includes(fieldKey, monotonic)) return isMonotonic(oldField, newField, fieldKey) + + if (_.includes(fieldKey, free)) { + if (_.isNil(newField)) return false + return true + } + + logger.error('This field [%s] should never change', fieldKey) + logger.error('oldField: %j', oldField) + logger.error('newField: %j', newField) + throw new Error(`This field [${fieldKey}] should never change`) +} + function diff (oldTx, newTx) { let updatedTx = {} - UPDATEABLE_FIELDS.forEach(fieldKey => { - if (oldTx && _.isEqualWith(nilEqual, oldTx[fieldKey], newTx[fieldKey])) return + if (!oldTx) throw new Error('oldTx must not be null') + if (!newTx) throw new Error('newTx must not be null') - // We never null out an existing field - if (oldTx && _.isNil(newTx[fieldKey])) return + _.forEach(fieldKey => { + const oldField = oldTx[fieldKey] + const newField = newTx[fieldKey] + if (fieldKey === 'bills') return + if (_.isEqualWith(nilEqual, oldField, newField)) return - updatedTx[fieldKey] = newTx[fieldKey] - }) + if (!ensureRatchet(oldField, newField, fieldKey)) { + logger.warn('Value from lamassu-machine would violate ratchet [%s]', fieldKey) + logger.warn('Old tx: %j', oldTx) + logger.warn('New tx: %j', newTx) + return + } + + updatedTx[fieldKey] = newField + }, _.keys(newTx)) return updatedTx } @@ -85,6 +121,11 @@ function toObj (row) { return } + if (key === 'device_time') { + newObj[objKey] = parseInt(row[key], 10) + return + } + newObj[objKey] = row[key] }) @@ -128,14 +169,14 @@ function insertNewBills (billRows, tx) { .then(() => bills) } -function upsert (oldTx, tx) { +function upsert (oldTx, newTx) { if (!oldTx) { - return insert(tx) - .then(newTx => [oldTx, newTx]) + return insert(newTx) + .then(tx => [oldTx, tx]) } - return update(tx, diff(oldTx, tx)) - .then(newTx => [oldTx, newTx]) + return update(oldTx, diff(oldTx, newTx)) + .then(tx => [oldTx, tx]) } function insert (tx) { @@ -235,7 +276,6 @@ function monitorPending (settings) { } return db.any(sql, [PENDING_INTERVAL, MAX_PENDING]) - .then(_.tap(console.log)) .then(rows => Promise.all(_.map(processPending, rows))) .catch(logger.error) } diff --git a/lib/plugins/sms/twilio/twilio.js b/lib/plugins/sms/twilio/twilio.js index 76371804..d5c2e4d8 100644 --- a/lib/plugins/sms/twilio/twilio.js +++ b/lib/plugins/sms/twilio/twilio.js @@ -17,7 +17,6 @@ function sendMessage (account, rec) { from: account.fromNumber } - return client.sendMessage(opts) .catch(err => { if (_.includes(err.code, BAD_NUMBER_CODES)) { diff --git a/lib/wallet.js b/lib/wallet.js index b500db7f..6d0f73ae 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -44,15 +44,11 @@ function balance (settings, cryptoCode) { } function sendCoins (settings, toAddress, cryptoAtoms, cryptoCode) { - console.log('DEBUG40') return fetchWallet(settings, cryptoCode) .then(r => { - console.log('DEBUG41') return r.wallet.sendCoins(r.account, toAddress, cryptoAtoms, cryptoCode) .then(res => { - console.log('DEBUG42') mem.clear(module.exports.balance) - console.log('DEBUG43: %j', res) return res }) })