Fix up various flow issues.
This commit is contained in:
parent
08bd7da33f
commit
0d8a8547f5
8 changed files with 60 additions and 40 deletions
|
|
@ -88,7 +88,7 @@ function redeemableTxs (deviceId) {
|
||||||
and redeem=$2
|
and redeem=$2
|
||||||
and dispense=$3
|
and dispense=$3
|
||||||
and provisioned_1 is not null
|
and provisioned_1 is not null
|
||||||
and (extract(epoch from (now() - greatest(created, confirmation_time))) * 1000) < $4`
|
and (extract(epoch from (now() - greatest(created, confirmed_at))) * 1000) < $4`
|
||||||
|
|
||||||
return db.any(sql, [deviceId, true, false, REDEEMABLE_AGE])
|
return db.any(sql, [deviceId, true, false, REDEEMABLE_AGE])
|
||||||
.then(_.map(toObj))
|
.then(_.map(toObj))
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const logger = require('./logger')
|
||||||
const plugins = require('./plugins')
|
const plugins = require('./plugins')
|
||||||
const helper = require('./cash-out-helper')
|
const helper = require('./cash-out-helper')
|
||||||
const socket = require('./socket-client')
|
const socket = require('./socket-client')
|
||||||
|
const E = require('./error')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
post,
|
post,
|
||||||
|
|
@ -17,8 +18,8 @@ module.exports = {
|
||||||
cancel
|
cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
const UPDATEABLE_FIELDS = ['txHash', 'status', 'dispense', 'dispenseConfirmed',
|
const UPDATEABLE_FIELDS = ['txHash', 'txVersion', 'status', 'dispense', 'dispenseConfirmed',
|
||||||
'notified', 'redeem', 'phone', 'error', 'swept']
|
'notified', 'redeem', 'phone', 'error', 'swept', 'publishedAt', 'confirmedAt']
|
||||||
|
|
||||||
const STALE_INCOMING_TX_AGE = T.week
|
const STALE_INCOMING_TX_AGE = T.week
|
||||||
const STALE_LIVE_INCOMING_TX_AGE = 10 * T.minutes
|
const STALE_LIVE_INCOMING_TX_AGE = 10 * T.minutes
|
||||||
|
|
@ -37,7 +38,11 @@ function httpError (msg, code) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
function post (tx, pi) {
|
function selfPost (tx, pi) {
|
||||||
|
return post(tx, pi, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function post (tx, pi, fromClient = true) {
|
||||||
const TransactionMode = pgp.txMode.TransactionMode
|
const TransactionMode = pgp.txMode.TransactionMode
|
||||||
const isolationLevel = pgp.txMode.isolationLevel
|
const isolationLevel = pgp.txMode.isolationLevel
|
||||||
const tmSRD = new TransactionMode({tiLevel: isolationLevel.serializable})
|
const tmSRD = new TransactionMode({tiLevel: isolationLevel.serializable})
|
||||||
|
|
@ -48,6 +53,9 @@ function post (tx, pi) {
|
||||||
return t.oneOrNone(sql, [tx.id])
|
return t.oneOrNone(sql, [tx.id])
|
||||||
.then(toObj)
|
.then(toObj)
|
||||||
.then(oldTx => {
|
.then(oldTx => {
|
||||||
|
const isStale = fromClient && oldTx && (oldTx.txVersion >= tx.txVersion)
|
||||||
|
if (isStale) throw new E.StaleTxError('Stale tx')
|
||||||
|
|
||||||
return preProcess(oldTx, tx, pi)
|
return preProcess(oldTx, tx, pi)
|
||||||
.then(preProcessedTx => upsert(oldTx, preProcessedTx))
|
.then(preProcessedTx => upsert(oldTx, preProcessedTx))
|
||||||
})
|
})
|
||||||
|
|
@ -280,8 +288,33 @@ function postProcess (txVector, pi) {
|
||||||
return Promise.resolve({})
|
return Promise.resolve({})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPublished (status) {
|
||||||
|
return _.includes(status, ['published', 'rejected', 'authorized', 'instant', 'confirmed'])
|
||||||
|
}
|
||||||
|
|
||||||
|
function isConfirmed (status) {
|
||||||
|
return status === 'confirmed'
|
||||||
|
}
|
||||||
|
|
||||||
function updateStatus (oldTx, newTx) {
|
function updateStatus (oldTx, newTx) {
|
||||||
return _.set('status', ratchetStatus(oldTx.status, newTx.status), newTx)
|
const oldStatus = oldTx.status
|
||||||
|
const newStatus = ratchetStatus(oldStatus, newTx.status)
|
||||||
|
|
||||||
|
const publishedAt = !oldTx.publishedAt && isPublished(newStatus)
|
||||||
|
? 'now()^'
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const confirmedAt = !oldTx.confirmedAt && isConfirmed(newStatus)
|
||||||
|
? 'now()^'
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const updateRec = {
|
||||||
|
publishedAt,
|
||||||
|
confirmedAt,
|
||||||
|
status: newStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
return _.merge(newTx, updateRec)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ratchetStatus (oldStatus, newStatus) {
|
function ratchetStatus (oldStatus, newStatus) {
|
||||||
|
|
@ -311,8 +344,8 @@ function processTxStatus (tx, settings) {
|
||||||
const pi = plugins(settings, tx.deviceId)
|
const pi = plugins(settings, tx.deviceId)
|
||||||
|
|
||||||
return pi.getStatus(tx)
|
return pi.getStatus(tx)
|
||||||
.then(res => _.set('status', res.status, tx))
|
.then(res => _.assign(tx, {status: res.status}))
|
||||||
.then(_tx => post(_tx, pi))
|
.then(_tx => selfPost(_tx, pi))
|
||||||
}
|
}
|
||||||
|
|
||||||
function monitorLiveIncoming (settings) {
|
function monitorLiveIncoming (settings) {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const NAME = 'FakeWallet'
|
||||||
const SECONDS = 1000
|
const SECONDS = 1000
|
||||||
const PUBLISH_TIME = 2 * SECONDS
|
const PUBLISH_TIME = 2 * SECONDS
|
||||||
const AUTHORIZE_TIME = PUBLISH_TIME + 6 * SECONDS
|
const AUTHORIZE_TIME = PUBLISH_TIME + 6 * SECONDS
|
||||||
const CONFIRM_TIME = AUTHORIZE_TIME + 180 * SECONDS
|
const CONFIRM_TIME = AUTHORIZE_TIME + 120 * SECONDS
|
||||||
|
|
||||||
let t0
|
let t0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ function authorize (account, toAddress, cryptoAtoms, cryptoCode) {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (cryptoCode !== 'BTC') throw new Error('Unsupported crypto: ' + cryptoCode)
|
if (cryptoCode !== 'BTC') throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||||
|
|
||||||
const isAuthorized = true
|
const isAuthorized = false
|
||||||
return isAuthorized
|
return isAuthorized
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ function toCashOutTx (row) {
|
||||||
function fetchPhoneTx (phone) {
|
function fetchPhoneTx (phone) {
|
||||||
const sql = `select * from cash_out_txs
|
const sql = `select * from cash_out_txs
|
||||||
where phone=$1 and dispense=$2
|
where phone=$1 and dispense=$2
|
||||||
and (extract(epoch from (coalesce(confirmation_time, now()) - created))) * 1000 < $3`
|
and (extract(epoch from (coalesce(confirmed_at, now()) - created))) * 1000 < $3`
|
||||||
|
|
||||||
const values = [phone, false, TRANSACTION_EXPIRATION]
|
const values = [phone, false, TRANSACTION_EXPIRATION]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -188,19 +188,6 @@ function pair (req, res, next) {
|
||||||
.catch(next)
|
.catch(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
function phoneCode (req, res, next) {
|
|
||||||
const pi = plugins(req.settings, req.deviceId)
|
|
||||||
const phone = req.body.phone
|
|
||||||
|
|
||||||
return pi.getPhoneCode(phone)
|
|
||||||
.then(code => respond(req, res, {code}))
|
|
||||||
.catch(err => {
|
|
||||||
if (err.name === 'BadNumberError') throw httpError('Bad number', 410)
|
|
||||||
throw err
|
|
||||||
})
|
|
||||||
.catch(next)
|
|
||||||
}
|
|
||||||
|
|
||||||
function errorHandler (err, req, res, next) {
|
function errorHandler (err, req, res, next) {
|
||||||
const statusCode = err.name === 'HTTPError'
|
const statusCode = err.name === 'HTTPError'
|
||||||
? err.code || 500
|
? err.code || 500
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ const pify = require('pify')
|
||||||
const fs = pify(require('fs'))
|
const fs = pify(require('fs'))
|
||||||
const options = require('./options')
|
const options = require('./options')
|
||||||
const ph = require('./plugin-helper')
|
const ph = require('./plugin-helper')
|
||||||
const db = require('./db')
|
|
||||||
|
|
||||||
const FETCH_INTERVAL = 5000
|
const FETCH_INTERVAL = 5000
|
||||||
const INSUFFICIENT_FUNDS_CODE = 570
|
const INSUFFICIENT_FUNDS_CODE = 570
|
||||||
|
|
@ -111,27 +110,14 @@ function authorizeZeroConf (settings, tx, machineId) {
|
||||||
return zeroConf.authorize(account, tx.toAddress, tx.cryptoAtoms, tx.cryptoCode)
|
return zeroConf.authorize(account, tx.toAddress, tx.cryptoAtoms, tx.cryptoCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPublishAge (txId) {
|
|
||||||
const sql = `select extract(epoch from (now() - created)) * 1000 as age
|
|
||||||
from cash_out_actions
|
|
||||||
where tx_id=$1
|
|
||||||
and action=$2`
|
|
||||||
|
|
||||||
return db.oneOrNone(sql, [txId, 'published'])
|
|
||||||
.then(row => row && row.age)
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStatus (settings, tx, machineId) {
|
function getStatus (settings, tx, machineId) {
|
||||||
return getWalletStatus(settings, tx)
|
return getWalletStatus(settings, tx)
|
||||||
.then((statusRec) => {
|
.then((statusRec) => {
|
||||||
if (statusRec.status === 'authorized') {
|
if (statusRec.status === 'authorized') {
|
||||||
const promises = [
|
return authorizeZeroConf(settings, tx, machineId)
|
||||||
getPublishAge(tx.id),
|
.then(isAuthorized => {
|
||||||
authorizeZeroConf(settings, tx, machineId)
|
const publishAge = Date.now() - tx.publishedAt
|
||||||
]
|
|
||||||
|
|
||||||
return Promise.all(promises)
|
|
||||||
.then(([publishAge, isAuthorized]) => {
|
|
||||||
const unauthorizedStatus = publishAge < ZERO_CONF_EXPIRATION
|
const unauthorizedStatus = publishAge < ZERO_CONF_EXPIRATION
|
||||||
? 'published'
|
? 'published'
|
||||||
: 'rejected'
|
: 'rejected'
|
||||||
|
|
|
||||||
14
migrations/1505044429557-add_cash_out_txs_published_at.js
Normal file
14
migrations/1505044429557-add_cash_out_txs_published_at.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
var db = require('./db')
|
||||||
|
|
||||||
|
exports.up = function (next) {
|
||||||
|
const sql = [
|
||||||
|
'alter table cash_out_txs add column published_at timestamptz',
|
||||||
|
'alter table cash_out_txs rename column confirmation_time to confirmed_at'
|
||||||
|
]
|
||||||
|
|
||||||
|
db.multi(sql, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.down = function (next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue