From 8f081ebf00841239cf3970114eaeea61438adf86 Mon Sep 17 00:00:00 2001 From: Josh Harvey Date: Wed, 1 Jun 2016 14:45:58 +0300 Subject: [PATCH] implement HD sweep --- lib/plugins.js | 27 ++++++++++++++++++++ lib/postgresql_interface.js | 37 ++++++++++++++++++++++++++++ migrations/012-add-hd-path-serial.js | 3 ++- todo.txt | 1 + 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/lib/plugins.js b/lib/plugins.js index a9e0c27f..481bd74a 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -23,6 +23,8 @@ var UNNOTIFIED_INTERVAL = 60 * 1000 var MAX_NOTIFY_AGE = 48 * 60 * 60 * 1000 var MIN_NOTIFY_AGE = 5 * 60 * 1000 var TRANSACTION_EXPIRATION = 48 * 60 * 60 * 1000 +var SWEEP_LIVE_HD_INTERVAL = 60 * 1000 +var SWEEP_OLD_HD_INTERVAL = 60 * 60 * 1000 var db = null @@ -465,6 +467,8 @@ exports.startPolling = function startPolling () { setInterval(monitorLiveIncoming, LIVE_INCOMING_TX_INTERVAL) setInterval(monitorIncoming, INCOMING_TX_INTERVAL) setInterval(monitorUnnotified, UNNOTIFIED_INTERVAL) + setInterval(sweepLiveHD, SWEEP_LIVE_HD_INTERVAL) + setInterval(sweepOldHD, SWEEP_OLD_HD_INTERVAL) monitorLiveIncoming() monitorIncoming() @@ -775,3 +779,26 @@ exports.cachedResponse = function (session, path, method) { exports.cacheResponse = function (session, path, method, body) { return db.cacheResponse(session, path, method, body) } + +function sweepHD (row) { + const cryptoCode = row.crypto_code + const walletPlugin = walletPlugins[cryptoCode] + return walletPlugin.sweep(row.hdSerial) + .then(txHash => { + if (txHash) { + logger.debug('[%s] Swept address with tx: %s', cryptoCode, txHash) + return db.markSwept(row.session_id) + } + }) + .catch(err => console.error(err)) +} + +function sweepLiveHD () { + return db.fetchLiveHD() + .then(rows => Promise.all(rows.map(sweepHD))) +} + +function sweepOldHD () { + return db.fetchOldHD() + .then(rows => Promise.all(rows.map(sweepHD))) +} diff --git a/lib/postgresql_interface.js b/lib/postgresql_interface.js index 0d3511e6..89512b1d 100644 --- a/lib/postgresql_interface.js +++ b/lib/postgresql_interface.js @@ -8,6 +8,7 @@ const backoff = require('u-promised').backoff const logger = require('./logger') const CACHED_SESSION_TTL = 60 * 60 * 1000 +const LIVE_SWEEP_TTL = 48 * 60 * 60 * 1000 let db @@ -441,3 +442,39 @@ exports.nextCashOutSerialHD = function nextCashOutSerialHD (sessionId, cryptoCod return backoff(100, 0, 5, attempt) } + +exports.fetchLiveHD = function fetchLiveHD () { + const sql = `select * from cash_out_txs, cash_out_hds + where cash_out_txs.session_id=cash_out_hds.session_id + and status=$1 and swept=$2 and + ((extract(epoch from (now() - cash_out_txs.created))) * 1000)<$3` + + const values = ['confirmed', false, LIVE_SWEEP_TTL] + + return db.manyOrNone(sql, values) +} + +exports.fetchOldHD = function fetchLiveHD () { + db.one(`select reltuples as approximate_row_count from pg_class where relname = 'cash_out_txs'`) + .then(row => { + const rowCount = row.approximate_row_count + + const factor = rowCount < 1000 + ? 10 + : rowCount < 10000 ? 1 : 0.1 + + const sql = `select * from cash_out_txs tablesample system $1, + cash_out_hds + where cash_out_txs.session_id=cash_out_hds.session_id + and status=$2` + + const values = [factor, 'confirmed'] + + return db.manyOrNone(sql, values) + }) +} + +exports.markSwept = function markSwept (sessionId) { + const sql = `update cash_out_hds set swept=$1 where session_id=$2` + return db.none(sql, [true, sessionId]) +} diff --git a/migrations/012-add-hd-path-serial.js b/migrations/012-add-hd-path-serial.js index 2beb4b70..ad8ac2d4 100644 --- a/migrations/012-add-hd-path-serial.js +++ b/migrations/012-add-hd-path-serial.js @@ -6,8 +6,9 @@ exports.up = function (next) { session_id uuid PRIMARY KEY, crypto_code text NOT NULL, hd_serial integer NOT NULL, + swept boolean NOT NULL default false, created timestamptz NOT NULL default now(), - unique (crypto_code, hd_serial), + unique (crypto_code, hd_serial) )` ] db.multi(sql, next) diff --git a/todo.txt b/todo.txt index ade6827a..f4526ed8 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,4 @@ - l-m shouldn't keep polling l-s when not on pending screen (low priority) - scrutinize hkdf, maybe use own simplified version +- test geth cash-out