diff --git a/lib/postgresql_interface.js b/lib/postgresql_interface.js index d5289adb..b35275ee 100644 --- a/lib/postgresql_interface.js +++ b/lib/postgresql_interface.js @@ -190,10 +190,10 @@ function removePendingTx(client, sessionId, cb) { function insertOutgoingTx(client, deviceFingerprint, tx, totals, cb) { var sendAmount = computeSendAmount(tx, totals); var stage = 'partial_request'; - var source = tx.fiat ? 'machine' : 'timeout'; + var authority = tx.fiat ? 'machine' : 'timeout'; var satoshis = sendAmount.satoshis; var fiat = sendAmount.fiat; - insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, source, + insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, authority, function(err) { if (err) return cb(err); @@ -207,18 +207,18 @@ function insertOutgoingCompleteTx(client, deviceFingerprint, tx, cb) { if (!tx.fiat) return cb(); var stage = 'final_request'; - var source = 'machine'; + var authority = 'machine'; var satoshis = tx.satoshis; var fiat = tx.fiat; - insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, source, cb); + insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, authority, cb); } function insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, - source, cb) { + authority, cb) { var fields = [ 'session_id', 'stage', - 'source', + 'authority', 'incoming', 'device_fingerprint', 'to_address', @@ -232,7 +232,7 @@ function insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, var values = [ tx.txId, stage, - source, + authority, tx.incoming, deviceFingerprint, tx.toAddress, @@ -308,19 +308,19 @@ exports.sentCoins = function sentCoins(tx, satoshis, fee, error, txHash) { }); }; -exports.addIncomingTx = function addIncomingTx(deviceFingerprint, tx, source, +exports.addIncomingTx = function addIncomingTx(deviceFingerprint, tx, authority, satoshisReceived, cb) { connect(function(err, client, done) { - function maybeRemovePending(client, sessionId, source, cb) { - if (source === 'published') return cb(); + function maybeRemovePending(client, sessionId, authority, cb) { + if (authority === 'published') return cb(); removePendingTx(client, sessionId, cb); } if (err) return cb(err); async.waterfall([ async.apply(silentQuery, client, 'BEGIN', null), - async.apply(maybeRemovePending, client, tx.sessionId, source), - async.apply(insertTx, client, tx, satoshisReceived, 0, 'deposit', source) + async.apply(maybeRemovePending, client, tx.sessionId, authority), + async.apply(insertTx, client, tx, satoshisReceived, 0, 'deposit', authority) ], function(err) { if (err) { rollback(client, done); @@ -358,7 +358,7 @@ exports.addInitialIncoming = function addInitialIncoming(deviceFingerprint, tx, }; function lastTxStatus(client, deviceFingerprint, sessionId, cb) { - var sql = 'SELECT satoshis, source FROM transactions ' + + var sql = 'SELECT satoshis, authority FROM transactions ' + 'WHERE device_fingerprint=$1 AND session_id=$2 AND incoming=$3 ' + 'ORDER BY id DESC LIMIT 1'; var values = [deviceFingerprint, sessionId, true]; @@ -400,7 +400,7 @@ exports.dispenseStatus = function dispenseStatus(deviceFingerprint, sessionId, // TODO: handle multiple deposits var status = (lastTx.satoshis < requiredSatoshis) ? 'insufficientFunds' : - lastTx.source; + lastTx.authority; cb(null, status); }); }); diff --git a/migrations/001-initial.js b/migrations/001-initial.js index 8723c34d..e7ecb8ff 100644 --- a/migrations/001-initial.js +++ b/migrations/001-initial.js @@ -25,20 +25,6 @@ exports.up = function(next) { 'created timestamp NOT NULL DEFAULT now() ' + ')', - 'CREATE TABLE IF NOT EXISTS transactions ( ' + - 'id uuid PRIMARY KEY, ' + - 'status text NOT NULL, ' + - 'tx_hash text, ' + - 'device_fingerprint text, ' + - 'to_address text NOT NULL, ' + - 'satoshis integer, ' + - 'currency_code text, ' + - 'fiat decimal, ' + - 'error text, ' + - 'created timestamp NOT NULL DEFAULT now(), ' + - 'completed timestamp ' + - ')', - 'CREATE TABLE IF NOT EXISTS users ( ' + 'id serial PRIMARY KEY, ' + 'userName text NOT NULL UNIQUE, ' + diff --git a/migrations/004-transactions-reload.js b/migrations/004-transactions-reload.js index f04ed8bf..e787cc5e 100644 --- a/migrations/004-transactions-reload.js +++ b/migrations/004-transactions-reload.js @@ -8,32 +8,30 @@ exports.up = function(next) { var stages = ['initial_request', 'partial_request', 'final_request', 'partial_send', 'deposit', 'dispense_request', 'dispense']. map(singleQuotify).join(','); - var sources = ['timeout', 'machine', 'pending', 'published', + var authorizations = ['timeout', 'machine', 'pending', 'published', 'authorized', 'rejected'].map(singleQuotify).join(','); + var sqls = [ 'CREATE TYPE transaction_stage AS ENUM (' + stages + ')', - 'CREATE TYPE transaction_source AS ENUM (' + sources + ')', - 'ALTER TABLE transactions DROP IF EXISTS completed', - 'ALTER TABLE transactions DROP CONSTRAINT transactions_pkey', - 'ALTER TABLE transactions RENAME id TO session_id', - 'ALTER TABLE transactions ADD COLUMN id SERIAL', - 'UPDATE transactions SET id = DEFAULT', - 'ALTER TABLE transactions ADD PRIMARY KEY (id)', - 'CREATE INDEX ON transactions (session_id)', - 'ALTER TABLE transactions ADD COLUMN incoming boolean DEFAULT false', - 'ALTER TABLE transactions ADD COLUMN stage transaction_stage NULL', - 'ALTER TABLE transactions ADD COLUMN source transaction_source NULL', - 'ALTER TABLE transactions ADD COLUMN fee integer NOT NULL DEFAULT 0', - 'ALTER TABLE transactions ADD COLUMN error text NULL', - 'ALTER TABLE transactions ALTER COLUMN fiat SET DEFAULT 0', - 'ALTER TABLE transactions ALTER COLUMN satoshis SET DEFAULT 0', - 'ALTER TABLE transactions ALTER COLUMN fiat SET NOT NULL', - 'ALTER TABLE transactions ALTER COLUMN satoshis SET NOT NULL', - 'ALTER TABLE transactions ADD CONSTRAINT transactions_unique_source ' + - 'UNIQUE (session_id,to_address,stage,source)', + 'CREATE TYPE transaction_authority AS ENUM (' + authorizations + ')', - 'ALTER TABLE transactions DROP COLUMN status', - // Convert stages, source to NOT NULL + 'CREATE TABLE transactions ( ' + + 'id serial PRIMARY KEY, ' + + 'session_id uuid UNIQUE NOT NULL, ' + + 'device_fingerprint text, ' + + 'to_address text NOT NULL, ' + + 'satoshis integer NOT NULL DEFAULT 0, ' + + 'fiat decimal NOT NULL DEFAULT 0, ' + + 'currency_code text NOT NULL, ' + + 'fee integer NOT NULL DEFAULT 0, ' + + 'incoming boolean NOT NULL, ' + + 'stage transaction_stage NOT NULL, ' + + 'authority transaction_authority NOT NULL, ' + + 'tx_hash text, ' + + 'error text, ' + + 'created timestamp NOT NULL DEFAULT now(), ' + + 'UNIQUE (session_id, to_address, stage, authority) ' + + ')', 'CREATE TABLE pending_transactions ( ' + 'id serial PRIMARY KEY, ' + @@ -59,7 +57,13 @@ exports.up = function(next) { 'created timestamp NOT NULL DEFAULT now() ' + ')' ]; - db.multi(sqls, next); + + // Need to call this separately to ignore error + // in case transactions doesn't exist + var renameSql = 'ALTER TABLE transactions RENAME TO transactions_old'; + db.silentQuery(renameSql, function() { + db.multi(sqls, next); + }); }; exports.down = function(next) { diff --git a/migrations/db.js b/migrations/db.js index 16b76e8b..ae191313 100644 --- a/migrations/db.js +++ b/migrations/db.js @@ -10,14 +10,24 @@ exports.query = function query(sql, cb) { exports.multi([sql], cb); }; -exports.multi = function multi(sqls, cb) { +exports.silentQuery = function query(sql, cb) { pg.connect(conString, function(err, client, done) { - if (err) throw err; - - async.eachSeries(sqls, client.query.bind(client), function(err) { + if (err) return cb(err); + client.query(sql, function(err) { done(true); - if (err) throw err; - cb(); + cb(err); + }); + }); +}; + +exports.multi = function multi(sqls, cb) { + pg.connect(conString, function(err, client, done) { + if (err) return cb(err); + + async.eachSeries(sqls, client.query.bind(client), function(err) { + done(true); + if (err) console.log(err); + cb(err); }); }); };